home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / FWIM / LynxFWIM / LynxFWIM.c next >
Encoding:
Text File  |  1999-05-17  |  400.0 KB  |  12,744 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        LynxFWIM.c
  3.  
  4.     Contains:    Sample code for FWIM for Texas Instruments PCI-Lynx (TSB12LV21A)
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Eric Anderson
  13.  
  14.         Other Contact:        Clinton Bauder
  15.  
  16.         Technology:            FireWire
  17.  
  18.     Writers:
  19.  
  20.         (EA)    Eric Anderson (ewa)
  21.  
  22.     Change History (most recent first):
  23.  
  24.        <FW3>    12/21/98    EA        Copied in all the old check-in comments.
  25.        <FW2>    12/21/98    EA        Copied from branch <FW112a4> to main sources so we can build
  26.                                     different.
  27.        <FW1>    12/21/98    EA        first checked in
  28. */
  29.  
  30.  
  31. /////// Old check-in comments.
  32. //     <FW112a4>      9/4/98    DCB        Updating from main project base.
  33. //      <FW121>      9/3/98    CP        Under certain conditions the isoch interrupt handling logic
  34. //                                     could service an update or callproc twice in a row.  We now look
  35. //                                     if the last element of the previous queue is the first element
  36. //                                     of the next queue and punt it if necessary.
  37. //      <FW120>      9/1/98    DCB        Per <EA> don't clear RHB or CycleMaster immediately on finalize.
  38. //                                     Instead just clear Contender, shutdown the comparators and issue
  39. //                                     a reset. Then wait for root holdoff bit to go away. If it
  40. //                                     doesn't go away in say 100ms give up and just turn it off. We
  41. //                                     should wait longer but it probably doesn't matter and much
  42. //                                     longer will be noticeable during shutdown.
  43. //      <FW119>      9/1/98    DCB        Did two things. If a Read Request gets a link timeout then only
  44. //                                     retry once. This reduces the traffic after a reset for nodes
  45. //                                     that aren't responding. Second clear RHB, CycleMaster and
  46. //                                     Contender before Finalizing the FWIM. Also issue a bus reset
  47. //                                     after this so everybody knows we went away.
  48. //      <FW118>     8/31/98    DCB        Don't enable kLynxENA_POST_WR and kLynxENA_SLV_BURST since the
  49. //                                     errata for Rev A parts advises NOT to do this anymore. Also
  50. //                                     simplified the code when stopping a DCL program to just wait 2ms
  51. //                                     rather than using unsafe register accesses to watch for the FIFO
  52. //                                     to settle. Finally make the FWIM install correctly even if the
  53. //                                     PHY is unpowered.
  54. //      <FW116>     8/27/98    DCB        Fixing the maximum packet size for s400. Also we now depend on
  55. //                                     the buffers being allocated contiguously since they don't divide
  56. //                                     into page size anymore.
  57. //      <FW115>     8/25/98    DCB        Re-work the way we decide whether to load the FWIM based on PHY
  58. //                                     power state so we don't have any timers outstanding nor do we
  59. //                                     tell FSL about a reset on a FWIM that doesn't exist yet.
  60. //      <FW114>     8/24/98    EA        Added dispatch for FWGetCycleTime.
  61. //     <FW112a3>      8/4/98    jkl        Remove unnecessary include files.
  62. //     <FW112a2>     7/24/98    DCB        Roll in Eric's VM fix from the main sources.
  63. //      <FW113>     7/24/98    DCB        <EA> Fix an off-by-one™ error in the calculation of
  64. //                                     pLynxFWIMData->pageShift which was causing some
  65. //                                     PrepareMemoryForIO problems with VM on.
  66. //     <FW112a1>     7/20/98    DCB        Cleaned up this file for the SDK release.
  67. //      <FW112>     7/17/98    DCB        Added LynxFWIMSetFWIMState. This new API allows us to put FWIMs
  68. //                                     to sleep. This can be for the purpose of saving power or to
  69. //                                     "quiesce" the FWIM so it won't bother the FSL while the FSL is
  70. //                                     being replaced or fovr'd. Right now the call is pretty heavy
  71. //                                     handed and does a full reset when we go active again. This may
  72. //                                     not be necessary but I haven't thought it through enough yet.
  73. //                                     Meantime this will allow me to experiment with fovr'ing.
  74. //      <FW111>     7/15/98    DCB        Found the memory leak. Things allocated with
  75. //                                     MemAllocatePhysicallyContiguous need to be deallocated with
  76. //                                     MemDeallocatePhysicallyContiguous not PoolDeallocate.
  77. //      <FW110>     7/14/98    DCB        Implemented LynxFWIMFinalize which will be needed when we start
  78. //                                     replacing FWIMs that were in "ROM" from an extension. There's
  79. //                                     still some work to do as I've noticed a few memory leaks, but
  80. //                                     its mostly there. I'll track down the leaks tomorrow.
  81. //      <FW109>     7/13/98    EA        Changed to process local self ID from FujiFilm MF8404 PHY on
  82. //                                     some cards. Also made hardware power class depend on compile- time
  83. //                                     options.
  84. //      <FW108>      7/8/98    DCB        Made the FWIM more PCI-PCI bridge friendly be only reporting
  85. //                                     kIsrIsComplete from our interrupt handler if indeed we saw an
  86. //                                     interrupt. Otherwise we return kIsrIsNotComplete so sources
  87. //                                     further down the tree don't get starved. There are still some
  88. //                                     issues with interrupt polling which I don't know how to fix yet.
  89. //                                     Stay tuned.
  90. //      <FW106>      7/7/98    DCB        When getting the new node ID from the PHY we were endian
  91. //                                     swapping the damn thing once too many times. This led to well
  92. //                                     random node IDs which is, well, bad.
  93. //      <FW105>      7/7/98    DCB        Cleaned up error reporting back to FSL. We no longer pay
  94. //                                     attention to the errors returned from FWIMCommandIsComplete and
  95. //                                     instead always return the same error reported to
  96. //                                     FWIMCommandIsComplete. The returned error is only used for
  97. //                                     immediate calls anyway but for consistency we should always
  98. //                                     report the same thing sent from FWIMCommandIsComplete.
  99. //      <FW104>      7/5/98    EA        Add example of using csrROMUpdateInProgress during SetCSRROM.
  100. //                                     Added new feature info during initialize, including OpenHCI
  101. //                                     features and power features. Add other new dispatch table
  102. //                                     entries as sample code. Removed first-time bus reset during
  103. //                                     install.
  104. //      <FW103>      7/1/98    EA        Add dispatch entry for FWSetCSRROM, as an example for OpenHCI.
  105. //      <FW101>      7/1/98    DCB        Changed the parameters to LynxFWIMBuildAsyncTxPCL so that we
  106. //                                     pass in the ioPreparationTable instead of allocating it on the
  107. //                                     stack inside the function. CheckpointIO needs this structure and
  108. //                                     we don't call it til after we leave the function. As a result
  109. //                                     the table (which was on the stack) was no longer valid and we
  110. //                                     crashed. Also added some debugging info to keep track of the
  111. //                                     last 4 interrupts.
  112. //      <FW100>     6/25/98    DCB        Three changes. First clear pLynxFWIMData->pNextAsyncPCL in
  113. //                                     LynxFWIMFullReset so we correctly process incoming packets
  114. //                                     immediately instead of having to wait til we cycled through the
  115. //                                     list of PCLs. This way we wake up much quicker when the PHY
  116. //                                     becomes powered again. Second, delayed the reset after waking up
  117. //                                     the from PHY sleep to be more friendly. Third, got rid of the
  118. //                                     check for the transmitter becoming disabled when sync-wait for
  119. //                                     TX requests. The required register wasn't PHY safe so accessing
  120. //                                     it depended on the safe register access code which uses the TX
  121. //                                     channel. Now we just wait for the 50ms timeout to occur.
  122. //       <FW99>     6/23/98    DCB        The G3 problem turned out to be a speed issue. Apparently if you
  123. //                                     hit one of the "safe" registers quickly enough after the part
  124. //                                     stopped DMA because the PHY wasn't powered the Link generates a
  125. //                                     target abort. Grrr. Now we wait (an arbitrary) 25 microseconds
  126. //                                     before checking to see if the DMA stopped. Also fixed a rare but
  127. //                                     real uninitialized variable problem in LynxFWIMSafeRegisterRead.
  128. //       <FW98>     6/23/98    DCB        Made some progress on the safe register access front. We need to
  129. //                                     protect 0xA00 space registers too. Also, when we fail an access
  130. //                                     now we cancel the current transaction and return errors from
  131. //                                     subsequent commands until things look better. Every 5 seconds we
  132. //                                     try to reset everthing to see whether we have power. There are
  133. //                                     still at least 3 issues. First, it doesn't work on G3s. Second,
  134. //                                     the PHY needs to be powered during FWIM initialization or we
  135. //                                     won't load it. Finally, there are a couple of 0xA00 registers
  136. //                                     that apparently can't be accessed with DMA. I'm looking into
  137. //                                     just not using these registers but for now we assume if the PHY
  138. //                                     was powered just a few instructions ago it still is now.
  139. //       <FW97>     6/15/98    DCB        Fixed two things. Most importantly fixed a silly logical vs
  140. //                                     physical bug in LynxFWIMSafeRegisterRead which prevented us from
  141. //                                     working on some machines. Also fixed some cleanup code if we
  142. //                                     fail to allocate an isochronous channel and have to de-allocate
  143. //                                     it immediately.
  144. //       <FW96>      6/5/98    DCB        All registers above 0xB00 are now accessed with DMA rather than
  145. //                                     the memory map. This doesn't make the world safe for unpowered
  146. //                                     PHYs just yet, however. Now I have to figure out what to do when
  147. //                                     an access fails. We have to return all outstanding requests,
  148. //                                     shutdown any isoch channels and wait somehow for things to get
  149. //                                     better.
  150. //       <FW95>      6/4/98    DCB        Check in early, check in often... I'm done with the linkControl
  151. //                                     register and busNumberNodeNumber. I'm tired and want to go home
  152. //                                     so for now I'll check this in and get the rest of the registers
  153. //                                     tomorrow.
  154. //       <FW94>      6/2/98    DCB        Check in early, check in often... Use the safe register access
  155. //                                     routines when playing with the comparator registers. No action
  156. //                                     yet if the routines fail. Other registers above 0xB00 are up
  157. //                                     next.
  158. //       <FW93>     5/21/98    DCB        Fixed up LynxFWIMWaitAsyncTXFree to make it more readable.
  159. //                                     Instead of having a complicated "stop" scheme which works under
  160. //                                     all conditions we now pass in a set of conditions to wait for.
  161. //       <FW92>     5/21/98    DCB        Mostly finished writing the "Safe Register Access" routines that
  162. //                                     use DMA to access the Lynx registers above 0xB00. These are
  163. //                                     needed because if the PHY is unpowered accesses to these
  164. //                                     registers will bus error. Next I have to try and use them for
  165. //                                     something more than the PHYPowerCheck. After  that I have to
  166. //                                     write the code that sleeps the FWIM until the PHY is powered
  167. //                                     again.
  168. //       <FW91>     5/18/98    DCB        Re-work the interrupt enablers and disablers to make them safe
  169. //                                     for use with PCI-PCI bridges. Basically we turn them off at the
  170. //                                     chip now rather than use the default enablers. Otherwise we can
  171. //                                     end up with a spurious interrupt if we're disabled but the
  172. //                                     hardware causes an interrupt.
  173. //       <FW90>     5/12/98    DCB        Fix the version number. Why do they keep changing the spelling
  174. //                                     of these constants?
  175. //       <FW89>     5/12/98    DCB        Fixing up the PHY Reg Received stuff to plug a hole where we
  176. //                                     might not ever re-enable the receiver. Now we set a timer and if
  177. //                                     we don't get anymore resets after a while we turn the receiver
  178. //                                     on. The timer protects itself from further resets by keeping the
  179. //                                     comparators turned off.
  180. //     <FW78a7>     4/21/98    DCB        Added support for 1394-1995 style PHYs with >3 ports.
  181. //     <FW78a6>     4/20/98    DCB        Set speed to 400MBit if appropriate on XMit. 
  182. //     <FW78a5>      4/7/98    DCB        Cleaned up the PhyPowerCheck code a bit.
  183. //     <FW78a4>      4/6/98    DCB        Also fixed some stupid mistakes with the placement of the disable
  184. //                                     user code calls.
  185. //       <FW88>      4/8/98    jkl        Changed build stage in driver descriptor to final.
  186. //       <FW87>      4/3/98    DCB        Whoops, one minor bug in the last checkin. Checked the wrong ptr
  187. //                                     before disposing of allocated memory.
  188. //       <FW86>      4/2/98    DCB        Fix PhyPowerCheck to work when logical != physical (ie when VM
  189. //                                     is turned on or you are running on a Pex or Columbus machine.
  190. //     <FW78a3>     3/24/98    DCB        Rollins from TOT.
  191. //       <FW85>     3/24/98    jkl        Removed DebugStrs in PhyPowerCheck code.
  192. //       <FW84>     3/24/98    jkl        Added PhyPowerCheck routine using DMA to read the
  193. //                                     busNumberNodeNumber register.
  194. //     <FW78a2>     3/23/98    DCB        Allow more flexibility for assignments of DMA channels so we can
  195. //                                     use 3 for whatever combination of isochronous Xmit and Rcv we
  196. //                                     want. Also now don't run the SIH queues from the interrupt poll
  197. //                                     proc if we have marked ourselves busy. Many of the SIHs need to
  198. //                                     be synchronized and don't like re-entrancy.
  199. //       <FW83>      3/9/98    jkl        Changed error returned by AllocateIsochPort to paramErr per
  200. //                                     documentation.
  201. //       <FW82>      3/9/98    DCB        Adding support for TSB41LV06 PHY. Where apporpriate use extended
  202. //                                     PHY register set. Use self-id packet from bus rather than PHY
  203. //                                     registers. Set/Clear contender bit with PHY registers rather
  204. //                                     that GPIO if we have extended register set. Support 6 ports. Fix
  205. //                                     a race condition in self-id processing for both old and new
  206. //                                     PHYs.
  207. //       <FW81>     2/25/98    jkl        Removed bus reset holdoff. Causing problems with multiple machines.
  208. //       <FW80>     2/25/98    jkl        Correct inUse flag problem with bus reset request holdoff.
  209. //       <FW79>     2/24/98    jkl        Restore all previous changes except for ATF. Fix WriteATF
  210. //                                     Subtract routine so we actually wait a millisecond between each
  211. //                                     register read. Changed the bus reset request holdoff to be
  212. //                                     execution level safe. Five reset requests can be held, after
  213. //                                     that they return timeout error.
  214. //       <78a1>     2/19/98    DCB        Added lots of Enable and DisableVMUserCode calls so we work
  215. //                                     better as part of the backing store path. Fixed up the way we do
  216. //                                     interrupt polling so it actually works. Conditionalized this
  217. //                                     stuff so it doesn't break anything. Added some debug logging
  218. //                                     stuff as well.
  219. //         <78>      2/6/98    jkl        Backed out previous atf changes. Modified WriteATF to wait for
  220. //                                     much longer time before busying out. Fixes Panasonic camera
  221. //                                     problem. Added #ifdefs to build various versions of
  222. //                                     LynxLiteFWIM.
  223. //         <77>      2/1/98    jkl        Work on some FWIM updates: - unsafe resize FIFO code, pause
  224. //                                     asynch receiver - make the writeATF routine asynchronous -
  225. //                                     report the true power class - hold off reset requests for two
  226. //                                     seconds after receiving a reset - fix the start immediate option
  227. //                                     for isoch receive - AllocateLocalIsochronousPort should return
  228. //                                     an error if port is in use
  229. //       <FW76>     5/28/97    EA        Fixed rare case where FWIM jams because an unexpected "special
  230. //                                     ack" from Lynx leaves us in limbo.
  231. //       <FW75>      4/1/97    EA        Fixed recovery from async receive overflow by turning comparator
  232. //                                     back on after DMA is restarted.
  233. //       <FW74>     3/18/97    ES        Changed driver description version to final.
  234. //       <FW73>     3/10/97    EA        Added support for ReceivePacketOp.  Removed possibly dangerous
  235. //                                     debug messages from primary interrupt handlers.
  236. //       <FW72>     3/10/97    ES        Changed LynxFWIMUpdateDCLTimeStamp to add one cycle to
  237. //                                     compensate for work ahead. Increased maximum number of
  238. //                                     simultaneous queued interrupts to 100.
  239. //       <FW71>      3/6/97    EA        Changed ISO TX stop mechanism to eliminate aux commands and
  240. //                                     double PCLs, to reduce PCI latencies. Stop now uses check on
  241. //                                     ready bit before each packet. Also fixed GRF-jam recovery to
  242. //                                     actually work.
  243. //       <FW70>      3/5/97    EA        Changed to disable CYCMASTER faster (in primary interrupt
  244. //                                     handler) if we are no longer root after a bus reset, to reduce
  245. //                                     PHY jams. Added recovery mechanism for rare GRF-jam problem.
  246. //       <FW69>      3/3/97    ES        Added support for DCLTimeStamp.
  247. //       <FW68>     2/27/97    EA        Made changes to try to reduce vulnerability to PHY jams by
  248. //                                     eliminating redundant bus resets.
  249. //       <FW67>     2/18/97    EA        Changed how we send acks, and how we react to acks. Changed
  250. //                                     reset processing of new node ID. Added a bunch of comments about
  251. //                                     acks. Also removed LED-blinking code.
  252. //       <FW66>     2/14/97    ES        Added LynxFWIMFinalize and LynxFWIMPollInterrupts to plug in
  253. //                                     dispatch table.
  254. //       <FW65>     2/14/97    ES        Changed to mask out DCL opcode flags.
  255. //       <FW64>     2/13/97    EA        Commented out #define LynxFireBug for safety.
  256. //       <FW63>     2/12/97    EA        Changed transmit DMA to not hammer Lynx while waiting.
  257. //       <FW62>     2/11/97    EA        Added CRC-16 check of serial EEPROM contents.
  258. //       <FW61>      2/7/97    EA        Temporary hack to LynxFWIMGetRegisterBaseAddress
  259. //       <FW60>      2/6/97    EA        Added routines to load serial EEPROM to find global unique ID
  260. //                                     and other HW config info.
  261. //       <FW59>      2/6/97    ES        Removed use of status field in FWIMCommandParams record.
  262. //       <FW58>      2/4/97    ES        Changed LynxFWIMCreateAsyncTxDonePCLSegment to use logical lynx
  263. //                                     fwim data pointer instead of physical pointer when manually
  264. //                                     setting asyncTxDoneFlag.
  265. //       <FW57>     1/29/97    ES        Fixed implied return warning in LynxFWIMWriteTimer.
  266. //       <FW56>     1/29/97    ES        Added check for internal DMA transmit errors to
  267. //                                     LynxFWIMAckSecondaryInterruptHandler. Will schedule a transmit
  268. //                                     retry 10ms after detecting error.
  269. //       <FW55>     1/17/97    EA        Fixed AT DMA hang due to TX disable from bus reset during
  270. //                                     transmit
  271. //       <FW54>     1/15/97    EA        Fixed Open Firmware/Assigned-address matching bug
  272. //       <FW53>      1/9/97    ES        Changed LynxFWIMWriteATF to not explicitly start transmit DMA.
  273. //                                     This is done in LynxFWIMAddAsyncTxPCL and was causing DMA
  274. //                                     transmit problems.
  275. //       <FW52>      1/1/97    ES        Added support for updating DCL commands. Added support for
  276. //                                     servicing more than one isoch interrupt at a time.
  277. //       <FW51>    12/26/96    ES        Changed to use DCL program stop and release routines.
  278. //       <FW50>    12/20/96    ES        Cleaned up LynxFWIMWriteATF.
  279. //       <FW49>    12/18/96    ES        Changed GRF overflow handling to not flush GRF.
  280. //       <FW48>    12/26/96    ES        Consolidated some parameters in asynch FWIM commands and
  281. //                                     processing.
  282. //       <FW47>    12/22/96    ES        Changed IsochPortAction to IsochPortControl.
  283. //       <FW46>    12/12/96    ES        Took transmit buffer out of FWIMProcessAsynchParams record.
  284. //       <FW45>     12/6/96    ES        Changed FWIMInstallParams to FWIMInitializeParams and changed
  285. //                                     some of the fields in FWIMInitializeParams. Changed
  286. //                                     LynxFWIMInstall to LynxFWIMInitialize. FWIMAsynchCommandParams
  287. //                                     were changed to supply the split transaction timeout.
  288. //       <FW44>     12/6/96    ES        Changed the process read and lock response packet routines to
  289. //                                     return an error if the response code indicates an error.
  290. //       <FW43>     12/6/96    ES        Fixed a write to nil bug in LynxFWIMCompileDCLProgram.
  291. //       <FW42>    11/26/96    ES        Changed to use FWSetDCLProgramStartProc.
  292. //       <FW41>    11/26/96    ES        Changed LynxFWIMWriteATF to wait 100000 times. Changed
  293. //                                     LynxFWIMStartAsyncRxPCLProgram to wait for a fixed number of
  294. //                                     PCLs to become available before restarting the receive DMA.
  295. //       <FW40>    11/11/96    ES        Added LynxFWIMGetUniqueID.
  296. //       <FW39>     11/9/96    ES        Changed async receive mechanism. Async receive is disabled once
  297. //                                     we've used all the PCLs. PCLs are dynamically added back into
  298. //                                     the async receive program as they are freed.
  299. //       <FW38>     11/5/96    ES        Changed to use FireWire deferred tasks instead of secondary
  300. //                                     interrupts.
  301. //       <FW37>     11/5/96    ES        Fixed GRF overflow bug when stopping isoch receiving.
  302. //       <FW36>    10/27/96    EA        Fixed my checkin initials (D'oh!)
  303. //       <FW35>    10/27/96    EA        Added support for VM everywhere. Also added a lot of comments
  304. //       <FW34>    10/18/96    ES        Expanded DCL compiler notification proc. Added call to
  305. //                                     FWStartDCLProgram in LynxFWIMStartIsochPort.
  306. //       <FW33>     10/4/96    ES        Changed to use FWCallDCLCallProc.
  307. //       <FW32>     10/4/96    ES        Replaced DCLSetPacketAttributes with DCLSetTagSyncBits and added
  308. //                                     DCLSendPacketWithHeaderStart.
  309. //       <FW31>     10/3/96    ES        Changed to use FWIMPluginDispatchTable.
  310. //       <FW30>     10/3/96    ES        Got rid of LynxFWIMGetTopologyMap. We now call FWProcessSelfIDs.
  311. //                                     Tried to reduce problems with overflowing the ASYNC ring buffer.
  312. //       <FW29>     10/2/96    ES        Changed interrupt handling to only queue one secondary interrupt
  313. //                                     handler at a time per interrupt source.
  314. //       <FW28>     9/25/96    ES        Added asynchronous transaction response FWIM commands. Changed
  315. //                                     the way asynchronous requests are processed and responded to.
  316. //       <FW27>     9/16/96    ES        Took out some read response and isoch continue stuff.
  317. //       <FW26>     9/16/96    ES        Changed FWIM interface to return command acceptance.
  318. //       <FW25>     9/16/96    ES        Changed to use response code returned from
  319. //                                     FWProcessRead/Write/LockRequest.
  320. //       <FW24>     9/11/96    ES        Changed to use speed parameter passed in to asynchronous FWIM
  321. //                                     calls and to properly set local speed bits in topology map.
  322. //       <FW23>      9/5/96    ES        Changed to call FWProcessRead/Write/LockRequest asynchronously.
  323. //       <FW22>      9/3/96    ES        Added interface to send out link on packets.
  324. //       <FW21>     8/30/96    ES        Added enable/disable cycle master, set/clear root holdoff bit,
  325. //                                     send phy configuration packet, and other stuff to support
  326. //                                     isochronous resource management.
  327. //       <FW20>     8/29/96    ES        Added capability to set and clear contender bit and to
  328. //                                     accurately report state of contender bit in topology map. Also
  329. //                                     added support for handling lock requests.
  330. //       <FW19>     8/27/96    ES        Fixed a bug in LynxFWIMGetTopologyMap.
  331. //       <FW18>     8/26/96    ES        Conditionalize DebugStrs on FWDebugBuild.
  332. //       <FW17>     8/26/96    ES        Changed LynxFWIMGetTopologyMap to return local node ID.
  333. //       <FW16>     8/19/96    ES        Changed to use separate interrupt pDCLCallProc for each pcl
  334. //                                     program. Also changed to clear pDCLCallProc after it's been
  335. //                                     handled.
  336. //       <FW15>     8/16/96    ES        Implemented hack to treat ack pending as ack complete for
  337. //                                     sending write requests to fix mass storage driver.  Also changed
  338. //                                     stop isoch port to immediately set channel inactive for receive.
  339. //       <FW14>     8/16/96    ES        Changed LynxFWIMReleaseIsochPort to pass status in to
  340. //                                     FWIMCommandIsComplete.
  341. //       <FW13>     8/15/96    ES        Added compiler notificaton proc for DCL programs. Also added
  342. //                                     support for dynamically changing the destination of DCL jumps.
  343. //       <FW12>      8/8/96    ES        Improved error handling for allocating isochronous ports. Will
  344. //                                     now deallocate isoch port PCLs.
  345. //       <FW11>      8/8/96    ES        Changed to use DCL translation services.
  346. //       <FW10>      8/7/96    ES        Added option to build driver description for Lynx Lite.
  347. //        <FW9>      8/2/96    ES        Updated for more isochronous changes.
  348. //        <FW8>      8/1/96    ES        Took out unused local variables.
  349. //        <FW7>     7/31/96    ES        Changed to use new isochronous buffer architecture.
  350. //        <FW6>     7/11/96    ES        Added dynamic FIFO allocation for isochronous transmission and
  351. //                                     changed to handle ITF underflow better.
  352. //        <FW5>      7/8/96    ES        Added isoch transmit capability. Still need to work out FIFO
  353. //                                     sizing.
  354. //        <FW4>      7/2/96    EA        Made all DMA and PCLs cache-aligned, fixed
  355. //                                        cycle-master behavior, fixed DMA jam, fixed FIFO
  356. //                                     thresholds, etc.
  357. //        <FW3>     6/20/96    ES        Changed some comments.
  358. //        <FW2>     6/12/96    EA        Fill in contains and written by fields.
  359. //        <FW1>     6/12/96    EA        first checked in
  360. ///////
  361.  
  362.  
  363. // This was adapted from Erik's TIFWIM, long ago.
  364.  
  365. // TIP FOR BEST PERFORMANCE
  366. // Avoid touching Lynx registers.  Lynx may be in the middle of a DMA when you
  367. // do so, and it has to suspend that while it answers your query.  This leads
  368. // to FIFO underflows and overflows.  So touch registers only when there's no
  369. // other choice.  [Note: do as we say, not as we do.]
  370.  
  371. //#define DebugStr(x) strlen(x)
  372.  
  373.  
  374. #include <Types.h>
  375. #include <Errors.h>
  376. #include <Devices.h>
  377. #include <Interrupts.h>
  378. #include <PCI.h>
  379. #include <DriverServices.h>
  380. #include <FireWire.h>
  381. #include <LynxFWIM.h>
  382. /*zzz*/
  383. #include <stdio.h>
  384. char  debugStr[256];
  385. pascal void FWDebugStr(
  386.     ConstStr255Param            debuggerMsg)
  387. {
  388. #ifdef FW_DEBUG_BUILD
  389. #if FW_DEBUG_BUILD
  390.     DebugStr (debuggerMsg);
  391. #endif
  392. #endif
  393. }
  394. /*zzz*/
  395.  
  396. // Define this to check for Logical != Physical (use with VM off)
  397. //#define LynxVMDebug
  398.  
  399. // Define this to enable sending diagnostic messages to FireBug
  400. //#define LynxFireBug
  401.  
  402. #ifdef LynxFireBug
  403. char  fireBug[256];
  404. #endif
  405.  
  406. ////////////////////////////////////////////////////////////////////////////////
  407. //
  408. // Hardware-dependent definitions.  All of the power values are guesses.
  409. //
  410.  
  411. #ifdef LynxLiteFWIM
  412.     #if LynxLiteFWIM
  413.         #define PCINameProperty "\ppci104c,8003"
  414.         #define HardwareDeciWatts 60
  415.         #define HardwareMinDeciVolts 110
  416.         #define HardwareMaxDeciVolts 120
  417.         #define HardwarePowerClass kFWSelfIDBusPowered1W
  418.     #endif
  419. #endif
  420.  
  421.  
  422. ////////////////////////////////////////////////////////////////////////////////
  423. //
  424. // Internal procedure prototypes.
  425. //
  426.  
  427. static OSStatus    LynxFWIMInitialize (
  428.     FWIMInitializeParamsPtr        pFWIMInitializeParams);
  429.  
  430. static SInt32 LynxAllocateDMAChannel(
  431.     LynxFWIMDataPtr                pLynxFWIMData);
  432.     
  433. static void LynxDeAllocateDMAChannel(
  434.     LynxFWIMDataPtr                pLynxFWIMData,
  435.     SInt32                        dmaChannelNum);
  436.     
  437. static OSStatus    LynxFWIMFinalize (
  438.     FWIMFinalizeParamsPtr        pFWIMFinalizeParams);
  439.  
  440. static OSStatus    LynxFWIMPollInterrupts (
  441.     FWIMPollInterruptsParamsPtr    pFWIMPollInterruptsParams);
  442.  
  443. static OSStatus    LynxFWIMGetRegisterBaseAddress (
  444.     LynxFWIMDataPtr                pLynxFWIMData);
  445.  
  446. static OSStatus    LynxFWIMInstallInterruptHandler (
  447.     LynxFWIMDataPtr                pLynxFWIMData);
  448.  
  449. static UInt16 LynxFWIMcrc16(
  450.     UInt32                        *data,
  451.     UInt32                        count);
  452.     
  453. static void LynxFWIMControlEEPROM(
  454.     LynxFWIMDataPtr                pLynxFWIMData,
  455.     UInt32                        clock,
  456.     UInt32                        data,
  457.     UInt32                        timer);
  458.  
  459. static UInt32 LynxFWIMWaitForEEPROM(
  460.     LynxFWIMDataPtr                pLynxFWIMData);
  461.     
  462. static void LynxFWIMSendEEPROMBit(
  463.     LynxFWIMDataPtr                pLynxFWIMData,
  464.     UInt32                        bit);
  465.     
  466. static void LynxFWIMSendEEPROMByte(
  467.     LynxFWIMDataPtr                pLynxFWIMData,
  468.     UInt8                        sendByte);
  469.     
  470. static UInt32 LynxFWIMReadEEPROMBit(
  471.     LynxFWIMDataPtr                pLynxFWIMData);
  472.     
  473. static UInt8 LynxFWIMReadEEPROMByte(
  474.     LynxFWIMDataPtr                pLynxFWIMData);
  475.     
  476. static void LynxFWIMStartEEPROM (
  477.     LynxFWIMDataPtr                pLynxFWIMData);
  478.     
  479. static void LynxFWIMStopEEPROM (
  480.     LynxFWIMDataPtr                pLynxFWIMData);
  481.  
  482. static void LynxFWIMProcessEEPROM(
  483.     LynxFWIMDataPtr                pLynxFWIMData);
  484.  
  485. static void    LynxFWIMFullReset(void);
  486.  
  487. static OSStatus    LynxFWIMExceptionHandler (
  488.     ExceptionInformationPowerPC    *theException);
  489.  
  490. static InterruptMemberNumber    LynxFWIMInterruptHandler (
  491.     InterruptSetMember            interruptSet,
  492.     void                        *interruptRefCon,
  493.     UInt32                        interruptCount);
  494.  
  495. static InterruptSourceState    LynxFWIMInterruptDisabler(
  496.     InterruptSetMember            interruptSetMember,
  497.     void                        *interruptRefCon );
  498.  
  499. static void    LynxFWIMInterruptEnabler(
  500.     InterruptSetMember            interruptSetMember,
  501.     void                        *interruptRefCon );
  502.  
  503. static Boolean    LynxFWIMDispatchInterrupts (
  504.     LynxFWIMDataPtr                pLynxFWIMData);
  505.  
  506. static void LynxFWIMHandleDMAInterrupt(
  507.     LynxFWIMDataPtr                pLynxFWIMData,
  508.     UInt32                        dmaChannel );
  509.  
  510. static void    LynxFWIMHandleLinkInterrupt (
  511.     LynxFWIMDataPtr                pLynxFWIMData);
  512.  
  513. static void    LynxFWIMHandleResetInterrupt (
  514.     LynxFWIMDataPtr                pLynxFWIMData);
  515.  
  516. static void    LynxFWIMHandlePhyRegRcvdInterrupt (
  517.     LynxFWIMDataPtr                pLynxFWIMData,
  518.     UInt32                        interrupt);
  519.  
  520. static void LynxFWIMHandleMiscInterrupt(
  521.     LynxFWIMDataPtr                pLynxFWIMData);
  522.  
  523. static OSStatus LynxFWIMResetBus (
  524.     FWIMCommandParamsPtr        pFWIMCommandParams,
  525.     UInt32                        *pCommandAcceptance);
  526.  
  527. static OSStatus LynxFWIMSetContenderBit (
  528.     FWIMCommandParamsPtr        pFWIMCommandParams,
  529.     UInt32                        *pCommandAcceptance);
  530.  
  531. static OSStatus LynxFWIMClearContenderBit (
  532.     FWIMCommandParamsPtr        pFWIMCommandParams,
  533.     UInt32                        *pCommandAcceptance);
  534.  
  535. static OSStatus    LynxFWIMEnableCycleMaster (
  536.     FWIMCommandParamsPtr        pFWIMCommandParams,
  537.     UInt32                        *pCommandAcceptance);
  538.  
  539. static OSStatus    LynxFWIMDisableCycleMaster (
  540.     FWIMCommandParamsPtr        pFWIMCommandParams,
  541.     UInt32                        *pCommandAcceptance);
  542.  
  543. static OSStatus    LynxFWIMSetRootHoldoffBit (
  544.     FWIMCommandParamsPtr        pFWIMCommandParams,
  545.     UInt32                        *pCommandAcceptance);
  546.  
  547. static OSStatus    LynxFWIMClearRootHoldoffBit (
  548.     FWIMCommandParamsPtr        pFWIMCommandParams,
  549.     UInt32                        *pCommandAcceptance);
  550.  
  551. static OSStatus    LynxFWIMGetUniqueID (
  552.     FWIMGetUniqueIDParamsPtr    pFWIMGetUniqueIDParams,
  553.     UInt32                        *pCommandAcceptance);
  554.  
  555. static OSStatus    LynxFWIMSendLinkOnPacket (
  556.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  557.     UInt32                        *pCommandAcceptance);
  558.  
  559. static OSStatus    LynxFWIMSendPhyConfigurationPacket (
  560.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  561.     UInt32                        *pCommandAcceptance);
  562.  
  563. static OSStatus LynxFWIMSetCSRROM(
  564.     FWIMSetCSRROMParamsPtr        pFWIMSetCSRROMParams,
  565.     UInt32                        *pCommandAcceptance);
  566.  
  567. static OSStatus    LynxFWIMDoLocalCompareSwap(
  568.     FWIMCompareSwapParamsPtr    pFWIMCompareSwapParams);
  569.  
  570. static OSStatus LynxFWIMSetAsynchFilters(
  571.     FWIMSetAsynchFiltersParamsPtr    pFWIMSetAsynchFiltersParams);
  572.  
  573. static OSStatus LynxFWIMSetFWIMState(
  574.     FWIMSetFWIMStateParamsPtr    pFWIMSetFWIMStateParams);
  575.  
  576. static OSStatus    LynxFWIMGetCycleTime(
  577.     FWIMGetCycleTimeParamsPtr    pFWIMGetCycleTimeParams);
  578.  
  579. static void    LynxFWIMWritePhyRegister (
  580.     LynxFWIMDataPtr                pLynxFWIMData,
  581.     UInt8                        regAddress,
  582.     UInt8                        regData);
  583.  
  584. static UInt8    LynxFWIMReadPhyRegister (
  585.     LynxFWIMDataPtr                pLynxFWIMData,
  586.     UInt8                        regAddress);
  587.  
  588. static void LynxFWIMPrepareAsyncDMA(
  589.     LynxFWIMDataPtr                pLynxFWIMData,
  590.     UInt32                        channel);
  591.  
  592. static void LynxFWIMAddAsyncRxPCL (
  593.     LynxPCLPtr                    pPCL);
  594.  
  595. static void LynxFWIMCreateAsyncRxPCLProgram (
  596.     LynxFWIMDataPtr                pLynxFWIMData);
  597.  
  598. static void LynxFWIMCreateAsyncRxDummyPCL (
  599.     LynxFWIMDataPtr                pLynxFWIMData);
  600.  
  601. static void LynxFWIMCreateAsyncRxOverflowPCLSegment (
  602.     LynxFWIMDataPtr                pLynxFWIMData);
  603.  
  604. static void LynxFWIMStartAsyncRxPCLProgram (
  605.     LynxFWIMDataPtr                pLynxFWIMData,
  606.     LynxPCLPtr                    pStartPCL);
  607.  
  608. static void LynxFWIMAddAsyncTxPCL (
  609.     LynxPCLPtr                    pPCL);
  610.  
  611. static void LynxFWIMCreateAsyncTxDummyPCL (
  612.     LynxFWIMDataPtr                pLynxFWIMData);
  613.  
  614. static void LynxFWIMCreateAsyncTxDonePCLSegment (
  615.     LynxFWIMDataPtr                pLynxFWIMData);
  616.  
  617. static void LynxFWIMCreateAsyncTxDataPCL (
  618.     LynxFWIMDataPtr                pLynxFWIMData);
  619.  
  620. static void LynxFWIMStartAsyncTxPCLProgram (
  621.     LynxFWIMDataPtr                pLynxFWIMData,
  622.     LynxPCLPtr                    pStartPCL);
  623.  
  624. static OSStatus LynxFWIMSafeRegisterRead(
  625.     LynxFWIMDataPtr                pLynxFWIMData,
  626.     UInt32                        * registerAddress,
  627.     UInt32                        * registerData );
  628.  
  629. static OSStatus LynxFWIMSafeRegisterWrite( 
  630.     LynxFWIMDataPtr                pLynxFWIMData,
  631.     UInt32                        * registerAddress,
  632.     UInt32                        registerData );
  633.  
  634. static OSStatus LynxFWIMSetRegisterBits( 
  635.     LynxFWIMDataPtr                pLynxFWIMData,
  636.     UInt32                        * registerAddress,
  637.     UInt32                        registerData );
  638.  
  639. static OSStatus LynxFWIMClearRegisterBits( 
  640.     LynxFWIMDataPtr                pLynxFWIMData,
  641.     UInt32                        * registerAddress,
  642.     UInt32                        registerData );
  643.  
  644. static OSStatus LynxFWIMWaitAsyncTXFree( 
  645.     LynxFWIMDataPtr                pLynxFWIMData,
  646.     UInt32                        dmaChannel,
  647.     UInt32                        * waitFlag,
  648.     UInt32                        waitValue );
  649.     
  650. static OSStatus LynxFWIMSetLinkControl (
  651.     LynxFWIMDataPtr                pLynxFWIMData,
  652.     UInt32                        linkControl);
  653.  
  654. static OSStatus LynxFWIMSetLinkControlBits (
  655.     LynxFWIMDataPtr                pLynxFWIMData,
  656.     UInt32                        linkControl);
  657.  
  658. static OSStatus LynxFWIMClearLinkControlBits (
  659.     LynxFWIMDataPtr                pLynxFWIMData,
  660.     UInt32                        linkControl);
  661.  
  662. static void LynxFWIMSetAsyncRxComparatorMask1 (
  663.     LynxFWIMDataPtr                pLynxFWIMData,
  664.     UInt32                        mask1);
  665.  
  666. static OSStatus LynxFWIMWriteATF(
  667.     LynxFWIMDataPtr                pLynxFWIMData,
  668.     UInt32                        transmitType,
  669.     UInt32                        speed,
  670.     UInt32                        baseCount,
  671.     UInt32                        data1,
  672.     UInt32                        data2,
  673.     UInt32                        data3,
  674.     UInt32                        data4,
  675.     UInt32                        extCount,
  676.     UInt32                        *extData);
  677.  
  678. static OSStatus    LynxFWIMBuildAsyncTxPCL (
  679.     LynxFWIMDataPtr                pLynxFWIMData,
  680.     LynxPCLPtr                    pPCL,
  681.     IOPreparationTable            *ioPreparationTable,
  682.     UInt32                        pclControl,
  683.     Ptr                            buffer1,
  684.     UInt32                        size1,
  685.     Ptr                            buffer2,
  686.     UInt32                        size2);
  687.  
  688. static OSStatus    LynxFWIMRead (
  689.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  690.     UInt32                        *pCommandAcceptance);
  691.  
  692. static OSStatus    LynxFWIMReadResponse (
  693.     FWIMAsynchResponseCommandParamsPtr
  694.                                 pFWIMAsynchResponseCommandParams,
  695.     UInt32                        *pCommandAcceptance);
  696.  
  697. static OSStatus    LynxFWIMWriteTimer (
  698.     void                        *p1,
  699.     void                        *p2);
  700.  
  701. static OSStatus    LynxFWIMWrite (
  702.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  703.     UInt32                        *pCommandAcceptance);
  704.  
  705. static OSStatus    LynxFWIMWriteResponse (
  706.     FWIMAsynchResponseCommandParamsPtr
  707.                                 pFWIMAsynchResponseCommandParams,
  708.     UInt32                        *pCommandAcceptance);
  709.  
  710. static OSStatus    LynxFWIMLock (
  711.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  712.     UInt32                        *pCommandAcceptance);
  713.  
  714. static OSStatus    LynxFWIMLockResponse (
  715.     FWIMAsynchResponseCommandParamsPtr
  716.                                 pFWIMAsynchResponseCommandParams,
  717.     UInt32                        *pCommandAcceptance);
  718.  
  719. static Boolean    LynxFWIMIsCompilableDCLProgram (
  720.     DCLProgramID                dclProgramID);
  721.  
  722. static OSStatus LynxFWIMCompileDCLProgram (
  723.     LynxFWIMDataPtr                pLynxFWIMData,
  724.     DCLProgramID                dclProgramID,
  725.     UInt32                        pclChannelNum,
  726.     UInt32                        channelNum,
  727.     UInt32                        speed);
  728.  
  729. static OSStatus LynxFWIMAddDCL (
  730.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  731.     DCLCommandPtr                pDCLCommand);
  732.  
  733. static OSStatus LynxFWIMAddReceivePacketStartDCL (
  734.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  735.     DCLCommandPtr                pDCLCommand);
  736.  
  737. static OSStatus LynxFWIMAddReceivePacketDCL (
  738.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  739.     DCLCommandPtr                pDCLCommand);
  740.  
  741. static OSStatus LynxFWIMAddSendPacketStartDCL (
  742.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  743.     DCLCommandPtr                pDCLCommand);
  744.  
  745. static OSStatus LynxFWIMAddSendPacketWithHeaderStartDCL (
  746.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  747.     DCLCommandPtr                pDCLCommand);
  748.  
  749. static OSStatus LynxFWIMAddSendPacketDCL (
  750.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  751.     DCLCommandPtr                pDCLCommand);
  752.  
  753. static OSStatus LynxFWIMAddCallProcDCL (
  754.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  755.     DCLCommandPtr                pDCLCommand);
  756.  
  757. static OSStatus LynxFWIMAddJumpDCL (
  758.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  759.     DCLCommandPtr                pDCLCommand);
  760.  
  761. static OSStatus LynxFWIMUpdateDCLListDCL (
  762.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  763.     DCLCommandPtr                pDCLCommand);
  764.  
  765. static OSStatus LynxFWIMTimeStampDCL (
  766.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  767.     DCLCommandPtr                pDCLCommand);
  768.  
  769. static OSStatus    LynxFWIMPCLStart (
  770.     LynxFWIMDataPtr                pLynxFWIMData,
  771.     LynxPCLBuildStatePtr        *ppLynxPCLBuildState,
  772.     LynxPCLPtr                    *ppPCL);
  773.  
  774. static OSStatus LynxFWIMAddLabelDCL(
  775.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  776.     DCLCommandPtr                pDCLCommand);
  777.  
  778. static OSStatus LynxFWIMAddSetTagSyncBitsDCL (
  779.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  780.     DCLCommandPtr                pDCLCommand);
  781.  
  782. static OSStatus    LynxFWIMPCLAllocateWord (
  783.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  784.     UInt32                        **ppWord);
  785.  
  786. static OSStatus    LynxFWIMPCLNew (
  787.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  788.     LynxPCLPtr                    *ppPCL,
  789.     UInt32                        refCon);
  790.  
  791. static OSStatus    LynxFWIMPCLNewIsochReceive (
  792.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  793.     LynxPCLPtr                    *ppPCL,
  794.     UInt32                        refCon,
  795.     UInt32                        speed);
  796.  
  797. static OSStatus    LynxFWIMPCLNewIsochTransmit (
  798.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  799.     LynxPCLPtr                    *ppPCL,
  800.     UInt32                        refCon,
  801.     UInt32                        speed);
  802.  
  803. static OSStatus    LynxFWIMPCLExtend (
  804.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  805.     UInt32                        pclType);
  806.  
  807. static OSStatus    LynxFWIMPCLLoadTemp (
  808.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  809.     Ptr                            pSource);
  810.  
  811. static OSStatus    LynxFWIMPCLStoreTemp (
  812.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  813.     Ptr                            pDest);
  814.  
  815. static OSStatus    LynxFWIMPCLStore0 (
  816.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  817.     Ptr                            pDest);
  818.  
  819. static OSStatus    LynxFWIMPCLStore1 (
  820.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  821.     Ptr                            pDest);
  822.  
  823. static OSStatus    LynxFWIMPCLCompareTemp16WithMask (
  824.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  825.     UInt16                        compareValue,
  826.     UInt16                        compareMask);
  827.  
  828. static OSStatus    LynxFWIMPCLBranchIfEqual (
  829.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  830.     DCLLabelPtr                    pDCLLabel);
  831.  
  832. static OSStatus    LynxFWIMPCLJump (
  833.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  834.     DCLLabelPtr                    pDCLLabel,
  835.     Ptr                            *ppPCLCommand);
  836.  
  837. static OSStatus    LynxFWIMPCLInterrupt (
  838.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  839.     DCLCommandPtr                pDCLCommand,
  840.     Ptr                            *ppPCLCommand);
  841.  
  842. static OSStatus    LynxFWIMPCLAuxCommand (
  843.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  844.     UInt32                        auxCommand,
  845.     UInt32                        waitBranchCondition,
  846.     UInt32                        auxParam);
  847.  
  848. static OSStatus    LynxFWIMPCLAddTransferBuffer (
  849.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  850.     Ptr                            buffer,
  851.     UInt32                        bufferSize,
  852.     Ptr                            *ppPCLCommand,
  853.     UInt32                        bufferAddrType);
  854.  
  855. static OSStatus    LynxFWIMResolveDCLLabel (
  856.     DCLLabelPtr                    pDCLLabel);
  857.  
  858. static LynxPCLPtr    LynxFWIMGetDCLLabelPCLPtr (
  859.     DCLLabelPtr                    pDCLLabel);
  860.  
  861. static OSStatus    LynxFWIMPCLLabel (
  862.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  863.     DCLLabelPtr                    pDCLLabel);
  864.  
  865. static LynxPCLPtr    LynxFWIMGetPCLFromDCL (
  866.     DCLCommandPtr                pDCLCommand);
  867.  
  868. static OSStatus        LynxFWIMDCLCompilerNotification (
  869.     DCLProgramID                dclProgramID,
  870.     UInt32                        notificationType,
  871.     DCLCommandPtr                *dclCommandList,
  872.     UInt32                        numDCLCommands);
  873.  
  874. static OSStatus        LynxFWIMDCLCompilerUpdateNotification (
  875.     DCLProgramID                dclProgramID,
  876.     DCLCommandPtr                *dclCommandList,
  877.     UInt32                        numDCLCommands);
  878.  
  879. static OSStatus        LynxFWIMUpdateDCLTimeStamp (
  880.     DCLCommandPtr                pDCLCommand);
  881.  
  882. static OSStatus        LynxFWIMDCLCompilerModifyNotification (
  883.     DCLProgramID                dclProgramID,
  884.     DCLCommandPtr                *dclCommandList,
  885.     UInt32                        numDCLCommands);
  886.  
  887. static OSStatus    LynxFWIMAllocatePCLBuildState (
  888.     LynxFWIMDataPtr                pLynxFWIMData,
  889.     LynxPCLBuildStatePtr        *ppLynxPCLBuildState);
  890.  
  891. static OSStatus    LynxFWIMAllocatePCL (
  892.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  893.     LynxPCLPtr                    *ppPCL);
  894.  
  895. static void LynxFWIMDeallocatePCLPools (
  896.     LynxPCLPoolDataPtr            pLynxPCLPoolDataList);
  897.  
  898. static void    LynxFWIMRunDCLProgram (
  899.     LynxIsochPortDataPtr        pLynxIsochPortData,
  900.     Ptr                            packetBuffer,
  901.     UInt32                        packetSize,
  902.     DCLCommandPtr                *ppDCLCommand);
  903.  
  904. static void    LynxFWIMDCLReceivePacketStart (
  905.     Ptr                            *pPacketBuffer,
  906.     UInt32                        *pPacketSize,
  907.     DCLCommandPtr                *ppDCLCommand,
  908.     Boolean                        *pWaitForPacket);
  909.  
  910. static void    LynxFWIMDCLReceiveBuffer (
  911.     Ptr                            *pPacketBuffer,
  912.     UInt32                        *pPacketSize,
  913.     DCLCommandPtr                *ppDCLCommand,
  914.     Boolean                        *pWaitForPacket);
  915.  
  916. static OSStatus LynxFWIMAllocateIsochPort (
  917.     FWIMAllocateIsochPortParamsPtr
  918.                                 pFWIMAllocateIsochPortParams,
  919.     UInt32                        *pCommandAcceptance);
  920.  
  921. static OSStatus LynxFWIMReleaseIsochPort (
  922.     FWIMReleaseIsochPortParamsPtr
  923.                                 pFWIMReleaseIsochPortParams,
  924.     UInt32                        *pCommandAcceptance);
  925.  
  926. static OSStatus _LynxFWIMReleaseIsochPort (
  927.     LynxFWIMDataPtr                pLynxFWIMData,
  928.     LynxIsochPortDataPtr        pLynxIsochPortData);
  929.  
  930. static OSStatus LynxFWIMStartIsochPort (
  931.     FWIMIsochPortControlParamsPtr
  932.                                 pFWIMIsochPortControlParams,
  933.     UInt32                        *pCommandAcceptance);
  934.  
  935. static OSStatus LynxFWIMStopIsochPort (
  936.     FWIMIsochPortControlParamsPtr
  937.                                 pFWIMIsochPortControlParams,
  938.     UInt32                        *pCommandAcceptance);
  939.  
  940. static OSStatus LynxFWIMStartTalkingDCLProgram (
  941.     DCLProgramID                dclProgramID);
  942.  
  943. static OSStatus LynxFWIMStartListeningDCLProgram (
  944.     DCLProgramID                dclProgramID);
  945.  
  946. static OSStatus LynxFWIMStopTalkingDCLProgram (
  947.     DCLProgramID                dclProgramID);
  948.  
  949. static OSStatus LynxFWIMStopListeningDCLProgram (
  950.     DCLProgramID                dclProgramID);
  951.  
  952. static OSStatus LynxFWIMReleaseDCLProgram (
  953.     DCLProgramID                dclProgramID);
  954.  
  955. static OSStatus    LynxFWIMReadRequestTimeoutHandler (
  956.     void                        *p1,
  957.     void                        *p2);
  958.  
  959. static OSStatus    LynxFWIMWriteRequestTimeoutHandler (
  960.     void                        *p1,
  961.     void                        *p2);
  962.  
  963. static OSStatus    LynxFWIMLockRequestTimeoutHandler (
  964.     void                        *p1,
  965.     void                        *p2);
  966.  
  967. static void    LynxFWIMDeferredTaskMultiplexer(
  968.     void                        *p1,
  969.     void                        *p2);
  970.  
  971. static void    LynxFWIMDMAAsyncPCLDeferredTask(
  972.     void                        *p1,
  973.     void                        *p2);
  974.  
  975.  
  976. static void    LynxFWIMDMAIsochReceivePCLDeferredTask(
  977.     void                        *p1,
  978.     void                        *p2);
  979.     
  980. static void    LynxFWIMDMAIsochTransmitDeferredTask(
  981.     void                        *p1,
  982.     void                        *p2);
  983.     
  984. static void    LynxFWIMResetDeferredTask (
  985.     void                        *p1,
  986.     void                        *p2);
  987.     
  988. static OSStatus    LynxFWIMDelayedReset(
  989.     void                        *p1,
  990.     void                        *p2);
  991.  
  992. static OSStatus    LynxFWIMDelayedPhyRegReceived(
  993.     void                        *p1,
  994.     void                        *p2);
  995.  
  996. static OSStatus    LynxFWIMHoldoffResetRequests(
  997.     void                        *p1,
  998.     void                        *p2);
  999.  
  1000. static void    LynxFWIMMiscInterruptDeferredTask (
  1001.     void                        *p1,
  1002.     void                        *p2);
  1003.  
  1004. static OSStatus    LynxFWIMAckSecondaryInterruptHandler (
  1005.     void                        *p1,
  1006.     void                        *p2);
  1007.  
  1008. static void LynxFWIMInformFSLofSelfIDs(
  1009.     LynxFWIMDataPtr                pLynxFWIMData );
  1010.  
  1011. static void LynxFWIMProcessPacket (
  1012.     LynxFWIMDataPtr                pLynxFWIMData,
  1013.     LynxPCLPtr                    pPCL,
  1014.     Ptr                            packetBuffer,
  1015.     UInt32                        packetSize);
  1016.  
  1017. static void    LynxFWIMProcessSelfIDPacket (
  1018.     LynxFWIMDataPtr                pLynxFWIMData,
  1019.     LynxPCLPtr                    pPCL,
  1020.     Ptr                            packetBuffer,
  1021.     UInt32                        packetSize);
  1022.  
  1023. static void    LynxFWIMProcessWriteQuadletPacket (
  1024.     LynxFWIMDataPtr                pLynxFWIMData,
  1025.     LynxPCLPtr                    pPCL,
  1026.     Ptr                            packetBuffer,
  1027.     UInt32                        packetSize);
  1028.  
  1029. static void    LynxFWIMProcessWriteQuadletRequestCompletionProc (
  1030.     FWIMProcessParamsPtr        pFWIMProcessParams);
  1031.  
  1032. static void    LynxFWIMProcessWriteBlockPacket (
  1033.     LynxFWIMDataPtr                pLynxFWIMData,
  1034.     LynxPCLPtr                    pPCL,
  1035.     Ptr                            packetBuffer,
  1036.     UInt32                        packetSize);
  1037.  
  1038. static void    LynxFWIMProcessWriteBlockRequestCompletionProc (
  1039.     FWIMProcessParamsPtr        pFWIMProcessParams);
  1040.  
  1041. static void    LynxFWIMProcessWriteResponsePacket (
  1042.     LynxFWIMDataPtr                pLynxFWIMData,
  1043.     LynxPCLPtr                    pPCL,
  1044.     Ptr                            packetBuffer,
  1045.     UInt32                        packetSize);
  1046.  
  1047. static void    LynxFWIMProcessReadQuadletPacket (
  1048.     LynxFWIMDataPtr                pLynxFWIMData,
  1049.     LynxPCLPtr                    pPCL,
  1050.     Ptr                            packetBuffer,
  1051.     UInt32                        packetSize);
  1052.  
  1053. static void    LynxFWIMProcessReadQuadletRequestCompletionProc (
  1054.     FWIMProcessParamsPtr        pFWIMProcessParams);
  1055.  
  1056. static void    LynxFWIMProcessReadBlockPacket (
  1057.     LynxFWIMDataPtr                pLynxFWIMData,
  1058.     LynxPCLPtr                    pPCL,
  1059.     Ptr                            packetBuffer,
  1060.     UInt32                        packetSize);
  1061.  
  1062. static void    LynxFWIMProcessReadBlockRequestCompletionProc (
  1063.     FWIMProcessParamsPtr        pFWIMProcessParams);
  1064.  
  1065. static void    LynxFWIMProcessReadQuadletResponsePacket (
  1066.     LynxFWIMDataPtr                pLynxFWIMData,
  1067.     LynxPCLPtr                    pPCL,
  1068.     Ptr                            packetBuffer,
  1069.     UInt32                        packetSize);
  1070.  
  1071. static void    LynxFWIMProcessReadBlockResponsePacket (
  1072.     LynxFWIMDataPtr                pLynxFWIMData,
  1073.     LynxPCLPtr                    pPCL,
  1074.     Ptr                            packetBuffer,
  1075.     UInt32                        packetSize);
  1076.  
  1077. static void    LynxFWIMProcessLockPacket (
  1078.     LynxFWIMDataPtr                pLynxFWIMData,
  1079.     LynxPCLPtr                    pPCL,
  1080.     Ptr                            packetBuffer,
  1081.     UInt32                        packetSize);
  1082.  
  1083. static void    LynxFWIMProcessLockRequestCompletionProc (
  1084.     FWIMProcessParamsPtr        pFWIMProcessParams);
  1085.  
  1086. static void    LynxFWIMProcessIsochronousBlockPacket (
  1087.     LynxFWIMDataPtr                pLynxFWIMData,
  1088.     LynxPCLPtr                    pPCL,
  1089.     Ptr                            packetBuffer,
  1090.     UInt32                        packetSize);
  1091.  
  1092. static void    LynxFWIMProcessLockResponsePacket (
  1093.     LynxFWIMDataPtr                pLynxFWIMData,
  1094.     LynxPCLPtr                    pPCL,
  1095.     Ptr                            packetBuffer,
  1096.     UInt32                        packetSize);
  1097.  
  1098. static void    LynxFWIMSetupFIFOs (
  1099.     LynxFWIMDataPtr                pLynxFWIMData);
  1100.     
  1101. void LynxFWIMInterruptSetup(
  1102.     LynxFWIMDataPtr                pLynxFWIMData);
  1103.  
  1104. void LynxFWIMDisableVMUserCode( 
  1105.     LynxFWIMDataPtr                pLynxFWIMData);
  1106.     
  1107. void LynxFWIMEnableVMUserCode(
  1108.     LynxFWIMDataPtr                pLynxFWIMData);
  1109.     
  1110. static OSStatus LynxFWIMDisableComparators (
  1111.     LynxFWIMDataPtr                pLynxFWIMData );
  1112.  
  1113. static OSStatus LynxFWIMEnableComparators (
  1114.     LynxFWIMDataPtr                pLynxFWIMData );
  1115.  
  1116. void LynxFWIMWaitForPHYPower( 
  1117.     LynxFWIMDataPtr                pLynxFWIMData,
  1118.     Boolean                        sleepRequest);
  1119.  
  1120. static OSStatus    LynxFWIMAttemptPHYWakeup(
  1121.     void                        *p1,
  1122.     void                        *p2);
  1123.  
  1124. #ifdef LynxFireBug
  1125. static void LynxFWIMFireBugMsg (
  1126.     LynxFWIMDataPtr                pLynxFWIMData,
  1127.     char                         *msg);
  1128. #endif
  1129.  
  1130.  
  1131. ////////////////////////////////////////////////////////////////////////////////
  1132. //
  1133. // The driver descriptor.
  1134. //
  1135.  
  1136. DriverDescription                TheDriverDescription =
  1137. {
  1138.     kTheDescriptionSignature,
  1139.     kInitialDriverDescriptor,
  1140.     {
  1141.         PCINameProperty,            // This is a macro defined at the top of this file
  1142.         1, 1, developStage, 2,
  1143.     },
  1144.     {
  1145.         kDriverIsUnderExpertControl,
  1146.         "\pAppleFWIM",
  1147.     },
  1148.  
  1149.     1,
  1150.     kServiceCategoryFWIM,
  1151.     0,
  1152.     1,0,0,0
  1153. };
  1154.  
  1155.  
  1156. ////////////////////////////////////////////////////////////////////////////////
  1157. //
  1158. // The plug in dispatch table.
  1159. //
  1160.  
  1161. FWIMPluginDispatchTable            ThePluginDispatchTable =
  1162. {
  1163.     kFWIMPluginVersion11,
  1164.     LynxFWIMInitialize,
  1165.     LynxFWIMFinalize,
  1166.     LynxFWIMPollInterrupts,
  1167.     LynxFWIMSendLinkOnPacket,
  1168.     LynxFWIMSendPhyConfigurationPacket,
  1169.     LynxFWIMRead,
  1170.     LynxFWIMReadResponse,
  1171.     LynxFWIMWrite,
  1172.     LynxFWIMWriteResponse,
  1173.     LynxFWIMLock,
  1174.     LynxFWIMLockResponse,
  1175.     LynxFWIMAllocateIsochPort,
  1176.     LynxFWIMReleaseIsochPort,
  1177.     LynxFWIMStartIsochPort,
  1178.     LynxFWIMStopIsochPort,
  1179.     LynxFWIMResetBus,
  1180.     LynxFWIMSetContenderBit,
  1181.     LynxFWIMClearContenderBit,
  1182.     LynxFWIMEnableCycleMaster,
  1183.     LynxFWIMDisableCycleMaster,
  1184.     LynxFWIMSetRootHoldoffBit,
  1185.     LynxFWIMClearRootHoldoffBit,
  1186.     LynxFWIMGetUniqueID,
  1187.     LynxFWIMSetCSRROM,
  1188.     LynxFWIMDoLocalCompareSwap,
  1189.     LynxFWIMSetAsynchFilters,
  1190.     LynxFWIMSetFWIMState,
  1191.     LynxFWIMGetCycleTime
  1192. };
  1193.  
  1194.  
  1195. ////////////////////////////////////////////////////////////////////////////////
  1196. //
  1197. // LynxFWIMInitialize
  1198. //
  1199. //   This is the FWIM installer proc.  It allocates the FWIM data record, gets
  1200. // the register base address, installs the interrupt handler, enables the
  1201. // register memory space, sets the chip up to receive selfID packets,
  1202. // enables bus reset interrupts, and initiates a bus reset to get the topology
  1203. // map.
  1204. //zzz Clean up on error???
  1205. //zzz Do we always need to initiate a bus reset???
  1206. //
  1207.  
  1208. // Ugly - right now, LynxFWIMFullReset is called from some places where this value isn't available
  1209. static LynxFWIMDataPtr HACKdata;
  1210. static UInt32 NoPhyReset = 0;
  1211.  
  1212. static OSStatus    LynxFWIMInitialize(
  1213.     FWIMInitializeParamsPtr        pFWIMInitializeParams)
  1214. {
  1215.     LynxFWIMDataPtr                pLynxFWIMData;
  1216.     RegEntryIDPtr                pFWIMRegEntryID;
  1217.     Ptr                            p,p1;
  1218.     IOPreparationTable            *ioPrep;
  1219.     UInt32                        pageSize, totalAlloc;
  1220.     UInt32                        bufPages;
  1221.     UInt32                        pclsPerPage, pclPages;
  1222.     UInt32                        doBuf, offset;
  1223.     Ptr                            logPage, physPage;
  1224.     OSStatus                    status = noErr;
  1225.     UInt32                        dmaChannelNum;
  1226.     
  1227.     //DebugStr("\pStep twice and set r0=0 to load FWIM");
  1228.     //if( pFWIMInitializeParams->fwimSpecificData )
  1229.     //    return (-1);
  1230.     
  1231.     // Set our features.  This is for Lynx:
  1232.     pFWIMInitializeParams->fwimFeatures = kFWIMSetFWIMState;            // Knows how to go to sleep
  1233.     pFWIMInitializeParams->fwimCSRROMMapLength = 0;
  1234.  
  1235.     // OpenHCI 1.0 would do this:
  1236.     //pFWIMInitializeParams->fwimFeatures = kFWIMFeatureCSRROMMap |
  1237.     //                                        kFWIMFeatureIRM |
  1238.     //                                        kFWIMFeaturePhysicalDMA |
  1239.     //                                          kFWIMSetFWIMState |            // Knows how to go to sleep
  1240.     //                                        kFWIMFeatureAsynchFilters;
  1241.     //pFWIMInitializeParams->fwimCSRROMMapLength = 1024;
  1242.  
  1243.     // Set more features.  These are card/MLB dependent, not chip dependent.
  1244.     // These values come from macro definitions at the top of this file.
  1245.     pFWIMInitializeParams->fwimDeciWatts = HardwareDeciWatts;
  1246.     pFWIMInitializeParams->fwimDeciVoltsMinimum = HardwareMinDeciVolts;
  1247.     pFWIMInitializeParams->fwimDeciVoltsMaximum = HardwareMaxDeciVolts;
  1248.     
  1249.     // Allocate Lynx FWIM data.
  1250.     // Parts of this struct will be phyiscally addressed, so we need
  1251.     // to make sure those parts don't straddle a page boundary.  To
  1252.     // guarantee this, we put them first in the struct, and we'll
  1253.     // page-align the whole struct, and map the first page.
  1254.     
  1255.     pageSize = GetLogicalPageSize ();
  1256.     
  1257.     p = PoolAllocateResident (sizeof (LynxFWIMData) + pageSize, true);
  1258.     if (p)
  1259.     {
  1260.         p1 = (Ptr) (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1));    // page-align
  1261.         pLynxFWIMData = (LynxFWIMDataPtr) p1;
  1262.         
  1263.         pLynxFWIMData->baseFWIMDataPtr = p;    // Remember the original address returned by PoolAllocateResident
  1264.                                             // so we can de-allocate it later
  1265.         pLynxFWIMData->pageSize = pageSize;
  1266.         pLynxFWIMData->pageShift = 0;
  1267.         while (pageSize >>= 1)
  1268.             pLynxFWIMData->pageShift++;
  1269.         pageSize = pLynxFWIMData->pageSize;
  1270.         
  1271.         ioPrep = &pLynxFWIMData->fwimDataIOPrep;
  1272.         ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  1273.         ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  1274.         ioPrep->granularity = 0;                                // do it all now
  1275.         ioPrep->firstPrepared = 0;
  1276.         ioPrep->mappingEntryCount = 1;                            // # of pages we will use
  1277.         ioPrep->logicalMapping = 0;
  1278.         ioPrep->physicalMapping = &pLynxFWIMData->fwimDataPhys;    // return phys addr
  1279.         ioPrep->rangeInfo.range.base = (void *) pLynxFWIMData;    // first addr to map
  1280.         ioPrep->rangeInfo.range.length = pageSize;                // map one page
  1281.         
  1282.         // there is no CheckpointIO which matches this.  It will be held down forever.
  1283.         status = PrepareMemoryForIO (ioPrep);
  1284.         if (status != noErr)
  1285.         {
  1286.             sprintf (debugStr, "FWIMData PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  1287.                      (long) status,
  1288.                      (long) ioPrep->rangeInfo.range.base,
  1289.                      (long) pLynxFWIMData->fwimDataPhys,
  1290.                      (long) ioPrep->rangeInfo.range.length);
  1291.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1292.         }
  1293.         
  1294.         if (status == noErr)
  1295.         {
  1296.             pFWIMInitializeParams->fwimSpecificData = (UInt32) pLynxFWIMData;
  1297.         }
  1298.         
  1299.     }
  1300.     else
  1301.     {
  1302.         status = memFullErr;
  1303.     }
  1304.  
  1305. // for FullReset, below
  1306.     HACKdata = pLynxFWIMData;
  1307.  
  1308.     // Get notification proc and name registry ID.
  1309.     if (status == noErr)
  1310.     {
  1311.         pLynxFWIMData->fwimID = pFWIMInitializeParams->fwimID;
  1312.         pLynxFWIMData->FWIMRegEntryID = pFWIMInitializeParams->fwimRegEntryID;
  1313.         pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
  1314.     }
  1315.  
  1316.     // Get register base address.
  1317.     if (status == noErr)
  1318.     {
  1319.         status = LynxFWIMGetRegisterBaseAddress (pLynxFWIMData);
  1320.     }
  1321.  
  1322.     
  1323.     // Note - sometimes these buffers are used to assemble response packets
  1324.     // So even if only a few quads are used in receiving, the rest of the buffer
  1325.     // may still be written to later (see LynxFWIMProcessReadBlockPacket, etc.)
  1326.     
  1327.     // Allocate async / self-ID buffers:
  1328.     // Buffers will not span page boundaries (for now, max rcv packet fits in a page)
  1329.     // and will be 32-byte aligned for best Lynx performance.  To save memory, alloc
  1330.     // one big buffer, prep it for I/O, and carve it up.  If marked for input, we can
  1331.     // re-use it over and over with no VM upkeep.  
  1332.     // PCLs are PCL-size-aligned, PCL-size is 128 and must divide the page size (easy).
  1333.     
  1334.     // Use a single allocation for async xmit/rcv buffers and xmit/rcv PCLs.  Marking
  1335.     // all the memory as "input | output" may prevent some optimizations - future feature.
  1336.     
  1337.     // Note, because we don't span page boundaries, we don't need to request contig
  1338.     // memory.  Change to ordinary allocate once it's working.  (Asynch Rx descriptors do span
  1339.     // pages, fix that first)
  1340.     
  1341.     if (status == noErr)
  1342.     {
  1343.         bufPages = ((kAsyncBufs * kPacketBufferSize) / pageSize) + 1;    // If packet size divides evenly remove the +1...
  1344.         pclsPerPage = pageSize / sizeof (LynxPCL);
  1345.         pclPages = (kAsyncBufs + pclsPerPage - 1) / pclsPerPage;
  1346.         
  1347.         totalAlloc = bufPages;                                // Space for async rcv bufs
  1348.         totalAlloc += 1;                                    // Space for async xmit buf
  1349.         totalAlloc += pclPages;                                // Space for async rcv PCLs
  1350.         totalAlloc += 1;                                    // Space for async xmit PCLs
  1351.         totalAlloc += 1;                                    // Space for register access PCLs
  1352.         totalAlloc += 1;                                    // Round up to page boundary
  1353.         
  1354.         // Use PoolAllocate to get a page table - don't use the stack.
  1355.         
  1356.         p = MemAllocatePhysicallyContiguous (totalAlloc * pageSize, true);
  1357.         
  1358.         if (!p)
  1359.         {
  1360.             status = memFullErr;
  1361.             sprintf (debugStr, "Async buf/PCL alloc failure, asked for %ld",
  1362.                      (long) totalAlloc * pageSize);
  1363.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1364.         }
  1365.         
  1366.         if (status == noErr)
  1367.         {
  1368.             // I think MemAllocatePhysicallyContiguous gives us memory starting
  1369.             // on a page boundary.  But just in case, align ourselves:
  1370.  
  1371.             pLynxFWIMData->basePCLData = p;
  1372.  
  1373.             p = (Ptr) ((((UInt32) p) + (pageSize - 1)) & ~(pageSize - 1));        // page-align
  1374.  
  1375.             // Mark this memory for Input, and learn the physical address    
  1376.             ioPrep = &pLynxFWIMData->ioPrep;
  1377.             ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  1378.             ioPrep->addressSpace = kCurrentAddressSpaceID;        // default
  1379.             ioPrep->granularity = 0;                            // do it all now
  1380.             ioPrep->firstPrepared = 0;
  1381.             ioPrep->mappingEntryCount = totalAlloc;                // # of pages we will use
  1382.             ioPrep->logicalMapping = 0;
  1383.             ioPrep->physicalMapping = pLynxFWIMData->physAddrs;    // return list of phys addrs
  1384.             ioPrep->rangeInfo.range.base = (void *) p;
  1385.             ioPrep->rangeInfo.range.length = totalAlloc * pageSize;
  1386.             
  1387.             // There is no CheckpointIO which matches this.  The buffers are ours for keeps.
  1388.             // !!! If we ever Finalize this FWIM then we need to checkpoint this guy!
  1389.             status = PrepareMemoryForIO (ioPrep);
  1390.             if (status != noErr)
  1391.             {
  1392.                 sprintf (debugStr, "PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  1393.                          (long) status,
  1394.                          (long) ioPrep->rangeInfo.range.base,
  1395.                          (long) pLynxFWIMData->physAddrs[0],
  1396.                          (long) ioPrep->rangeInfo.range.length);
  1397.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1398.             }
  1399.         }
  1400.  
  1401.         // Carve up what we got and store away the addrs
  1402.         if (status == noErr)
  1403.         {
  1404.             // Async rcv buffers (kAsyncBufs)
  1405.             
  1406.             logPage = p;
  1407.             physPage = (Ptr) pLynxFWIMData->physAddrs[0];
  1408.             
  1409.             for (doBuf = 0; doBuf < kAsyncBufs; doBuf++)
  1410.             {
  1411.                 offset = doBuf * kPacketBufferSize;
  1412.                 pLynxFWIMData->asyncBuf[doBuf] = logPage + offset;
  1413.                 pLynxFWIMData->asyncBufPhys[doBuf] = physPage + offset;
  1414.             }
  1415.             
  1416.             // Async xmit buffer (1)
  1417.             
  1418.             p += (bufPages * pageSize);
  1419.             pLynxFWIMData->asyncXmitBuf = p;
  1420.             pLynxFWIMData->asyncXmitBufPhys = pLynxFWIMData->physAddrs[bufPages];
  1421.             
  1422.             // Async rcv PCLs (kAsykcBufs)
  1423.             // WARNING rcv code assumes all PCLs are contiguous.
  1424.             // If made non-contig, will have to change several places
  1425.             
  1426.             p += pageSize;
  1427.             pLynxFWIMData->asyncPCL = (LynxPCL *) p;
  1428.             pLynxFWIMData->asyncPCLPhys = pLynxFWIMData->physAddrs[bufPages + 1];
  1429.             
  1430.             // Async xmit PCLs (3)
  1431.  
  1432.             p += (pclPages * pageSize);
  1433.             pLynxFWIMData->asyncXmitPCL = (LynxPCL *) p;
  1434.             pLynxFWIMData->asyncXmitPCLPhys = pLynxFWIMData->physAddrs[bufPages + 1 + pclPages];
  1435.                         
  1436.             // Register Access PCLs (6) 3 Dummy and 3 Real. 1 set each for task, SIH and interrupt level
  1437.             p += pageSize;
  1438.             pLynxFWIMData->phyRegAccessLog = (LynxPCL *) p;
  1439.             pLynxFWIMData->phyRegAccessPhys = pLynxFWIMData->physAddrs[bufPages + 2 + pclPages];
  1440.         }
  1441.     }
  1442.  
  1443.     // Allocate async receive PCL data records.
  1444.     if (status == noErr)
  1445.     {
  1446.         p = PoolAllocateResident (sizeof (LynxAsyncRxPCLData) * kAsyncBufs, true);
  1447.         
  1448.         if (p) {
  1449.             pLynxFWIMData->lynxAsyncRxPCLDataList = (LynxAsyncRxPCLDataPtr) p;
  1450.             pLynxFWIMData->baseRxData = p;
  1451.         }
  1452.         else
  1453.             status = memFullErr;
  1454.     }
  1455.  
  1456.     // Allocate async transmit PCL data records.
  1457.     if (status == noErr)
  1458.     {
  1459.         p = PoolAllocateResident (sizeof (LynxAsyncTxPCLData) * kNumAsyncTxPCLs, true);
  1460.         
  1461.         if (p) {
  1462.             pLynxFWIMData->lynxAsyncTxPCLDataList = (LynxAsyncTxPCLDataPtr) p;
  1463.             pLynxFWIMData->baseTxData = p;
  1464.         }
  1465.         else
  1466.             status = memFullErr;
  1467.     }
  1468.  
  1469.     // Set up async transmit PCLs.
  1470.     if (status == noErr)
  1471.     {
  1472.         LynxFWIMCreateAsyncTxDummyPCL (pLynxFWIMData);
  1473.         LynxFWIMCreateAsyncTxDonePCLSegment (pLynxFWIMData);
  1474.         LynxFWIMCreateAsyncTxDataPCL (pLynxFWIMData);
  1475.     }
  1476.  
  1477.     // Create deferred task for handling bus resets.
  1478.     if (status == noErr)
  1479.     {
  1480.         status = FWCreateDeferredTask (&(pLynxFWIMData->busResetDeferredTaskID),
  1481.                                        LynxFWIMResetDeferredTask,
  1482.                                        pLynxFWIMData);
  1483.     }
  1484.  
  1485.     // Assign each channel its default information
  1486.     for( dmaChannelNum = 0; dmaChannelNum < kNumDMAChannels; dmaChannelNum++ ) {
  1487.         pLynxFWIMData->DMAInfo[dmaChannelNum].channelType = kChannelUnused;
  1488.         pLynxFWIMData->DMAInfo[dmaChannelNum].inUse = false;
  1489.         // Create deferred task for each DMA channel. The LynxFWIMDeferredTaskMultiplexer figures out
  1490.         // which actual routine to run based on the type of DMA being performed on the channel.
  1491.         status = FWCreateDeferredTask (&(pLynxFWIMData->DMAInfo[dmaChannelNum].lynxDT),
  1492.                                        LynxFWIMDeferredTaskMultiplexer,
  1493.                                        pLynxFWIMData);
  1494.         if( status )
  1495.             break;
  1496.  
  1497.     }
  1498.     
  1499.     // Specific channel allocations:
  1500.     
  1501.     pLynxFWIMData->asyncRxDMA = kAsyncReceiveDMA;
  1502.     pLynxFWIMData->DMAInfo[pLynxFWIMData->asyncRxDMA].channelType = kAsyncRcv;
  1503.     pLynxFWIMData->DMAInfo[pLynxFWIMData->asyncRxDMA].inUse = true;
  1504.  
  1505.     pLynxFWIMData->asyncTxDMA = kAsyncTransmitDMA;
  1506.     pLynxFWIMData->DMAInfo[pLynxFWIMData->asyncTxDMA].channelType = kAsyncXmit;
  1507.     pLynxFWIMData->DMAInfo[pLynxFWIMData->asyncTxDMA].inUse = true;
  1508.     
  1509.     // Create deferred task for handling miscellaneous interrupts.
  1510.     if (status == noErr)
  1511.     {
  1512.         status = FWCreateDeferredTask (&(pLynxFWIMData->miscInterruptDeferredTaskID),
  1513.                                        LynxFWIMMiscInterruptDeferredTask,
  1514.                                        pLynxFWIMData);
  1515.     }
  1516.  
  1517.     // Install interrupt handler.
  1518.     if (status == noErr)
  1519.     {
  1520.         status = LynxFWIMInstallInterruptHandler (pLynxFWIMData);
  1521.     }
  1522.  
  1523.     // Use config space to enable bus mastering and memory space.
  1524.     if (status == noErr)
  1525.     {
  1526.         status = ExpMgrConfigWriteWord (
  1527.                     pFWIMRegEntryID, (LogicalAddress) cwCommand,
  1528.                     (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
  1529.     }
  1530.     
  1531.     if (status == noErr)
  1532.     {
  1533.         LynxFWIMFullReset();
  1534.     }
  1535.     
  1536.     return (status);
  1537. }
  1538.  
  1539.  
  1540. ////////////////////////////////////////////////////////////////////////////////
  1541. //
  1542. // LynxAllocateDMAChannel
  1543. //
  1544. //   Allocates a DMA channel.
  1545. //
  1546. static SInt32 LynxAllocateDMAChannel(
  1547.     LynxFWIMDataPtr                pLynxFWIMData)
  1548. {
  1549.     SInt32                        dmaChannelNum;
  1550.     
  1551.     // look for a free channel
  1552.     dmaChannelNum = kNumDMAChannels - 1;
  1553.     while( dmaChannelNum >= 0 ) {
  1554.         if( !pLynxFWIMData->DMAInfo[dmaChannelNum].inUse ) {
  1555.  
  1556.             pLynxFWIMData->DMAInfo[dmaChannelNum].inUse = true;
  1557.             break;
  1558.         }
  1559.         dmaChannelNum--;
  1560.     }
  1561.     
  1562.     return(dmaChannelNum);
  1563. }
  1564.     
  1565. ////////////////////////////////////////////////////////////////////////////////
  1566. //
  1567. // LynxDeAllocateDMAChannel
  1568. //
  1569. //   Deallocates a DMA channel
  1570. //
  1571. static void LynxDeAllocateDMAChannel(
  1572.     LynxFWIMDataPtr                pLynxFWIMData,
  1573.     SInt32                        dmaChannelNum)
  1574. {
  1575.  
  1576.     pLynxFWIMData->DMAInfo[dmaChannelNum].inUse = false;
  1577.     pLynxFWIMData->DMAInfo[dmaChannelNum].channelType = kChannelUnused;
  1578.  
  1579. }
  1580.  
  1581. ////////////////////////////////////////////////////////////////////////////////
  1582. //
  1583. // LynxFWIMFinalize
  1584. //
  1585. //   This is the FWIM finalizing proc.  It deallocates everything.
  1586. //   Presumes we only get called if we successfully initialized.
  1587. //
  1588.  
  1589. static OSStatus    LynxFWIMFinalize(
  1590.     FWIMFinalizeParamsPtr        pFWIMFinalizeParams)
  1591. {
  1592.     LynxFWIMDataPtr                pLynxFWIMData;
  1593.     LynxRegistersPtr            pLynxRegs;
  1594.     SInt32                        dmaChannelNum;
  1595.     UInt32                        lynxReg;
  1596.     UInt32                        phyReg;
  1597.     UInt32                        delay;
  1598.     AbsoluteTime                timeRemaining;
  1599.  
  1600.     // Get our internal data.
  1601.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMFinalizeParams->fwimSpecificData;
  1602.     pLynxRegs = pLynxFWIMData->pLynxRegisters;    
  1603.     
  1604.     // Clear Contender
  1605.     if( pLynxFWIMData->extendedPhyRegs ) {
  1606.         phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress);
  1607.         phyReg &= ~kLynxExtPhyCntd;
  1608.         LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress, phyReg);
  1609.     }
  1610.     else {
  1611.         // Program the contender bit to be clear on next reset.
  1612.         //zzz ought to have routine for setting gpios.
  1613.         lynxReg = EndianSwap32Bit (pLynxRegs->gpioControlA);
  1614.         lynxReg = (lynxReg & ~(kLynxGPIO_SRC0 | kLynxGPIO_POL_OUT0)) | kLynxGPIO_OUT_EN0;
  1615.         pLynxRegs->gpioControlA = EndianSwap32Bit (lynxReg);
  1616.         SynchronizeIO ();
  1617.         pLynxRegs->gpioData[1] = EndianSwapImm32Bit (0);
  1618.         SynchronizeIO ();
  1619.     }
  1620.  
  1621.     
  1622.     LynxFWIMDisableComparators(pLynxFWIMData);
  1623.  
  1624.     // Kill off interrupts since we won't be able to respond anymore.
  1625.     pLynxRegs->pciInterruptEnable = 0;
  1626.     
  1627.     // Issue a reset so everybody else knows our Link just went dark.
  1628.     // IBR reg is in the same spot for both old and extended PHY...
  1629.     phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyIBRAddress);
  1630.     phyReg |= kLynxPhyIBR;
  1631.     LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyIBRAddress, phyReg);
  1632.  
  1633.     // Wait for root holdoff bit to go away. If it doesn't go away in say 100ms give up and just turn it off.
  1634.     
  1635.     for( delay = 0; delay < 10; delay++ ) {
  1636.     
  1637.         phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyRHBAddress);
  1638.         if( phyReg & kLynxPhyRHB )
  1639.             break;
  1640.             
  1641.         DelayForHardware(DurationToAbsolute(durationMillisecond * 10));
  1642.     
  1643.     }
  1644.  
  1645.     if( delay >= 10 ) {
  1646.         // Clear the root holdoff bit in the PHY.  RHB reg is in the same spot for both old and extended PHY...
  1647.         phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyRHBAddress);
  1648.         phyReg &= ~kLynxPhyRHB;
  1649.         LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyRHBAddress, phyReg);
  1650.     }
  1651.  
  1652.     // Cancel any outstanding timers.
  1653.     
  1654.     if( pLynxFWIMData->holdoffResetRequestsTimerSet )
  1655.         CancelTimer (pLynxFWIMData->holdoffResetRequestsTimerID, &timeRemaining);
  1656.         
  1657.     if( pLynxFWIMData->requestTimeoutTimerSet )
  1658.         CancelTimer (pLynxFWIMData->requestTimeoutTimerID, &timeRemaining);
  1659.         
  1660.     if( pLynxFWIMData->delayedResetTimerSet )
  1661.         CancelTimer (pLynxFWIMData->delayedResetTimerID, &timeRemaining);
  1662.         
  1663.     if( pLynxFWIMData->phyRegTimerID )
  1664.         CancelTimer (pLynxFWIMData->phyRegTimerID, &timeRemaining);
  1665.         
  1666.     if( pLynxFWIMData->phyPowerTimerID )
  1667.         CancelTimer (pLynxFWIMData->phyPowerTimerID, &timeRemaining);    
  1668.  
  1669.     // Get rid of our deferred tasks
  1670.     for( dmaChannelNum = 0; dmaChannelNum < kNumDMAChannels; dmaChannelNum++ ) 
  1671.         FWDisposeDeferredTask( pLynxFWIMData->DMAInfo[dmaChannelNum].lynxDT );
  1672.     FWDisposeDeferredTask( pLynxFWIMData->miscInterruptDeferredTaskID );
  1673.     FWDisposeDeferredTask( pLynxFWIMData->busResetDeferredTaskID );
  1674.     
  1675.     // Checkpoint the PMFIO's we did when initializing the SIM.
  1676.     CheckpointIO (pLynxFWIMData->fwimDataIOPrep.preparationID, kNilOptions);
  1677.     CheckpointIO (pLynxFWIMData->ioPrep.preparationID, kNilOptions);
  1678.  
  1679.     // Put the interrupt functions back the way we found them.
  1680.     InstallInterruptFunctions
  1681.             (pLynxFWIMData->interruptSetMember.setID, 
  1682.              pLynxFWIMData->interruptSetMember.member,
  1683.              pLynxFWIMData->oldInterruptRefCon,
  1684.              pLynxFWIMData->oldInterruptHandler,
  1685.              pLynxFWIMData->interruptOldEnabler,
  1686.              pLynxFWIMData->interruptOldDisabler);
  1687.  
  1688.     // Make interrupt mananger think everything is turned off
  1689.     (*(pLynxFWIMData->interruptOldEnabler)) (pLynxFWIMData->interruptSetMember,
  1690.                                         pLynxFWIMData->oldInterruptRefCon);
  1691.                                         
  1692.     // Turn off access to the card's memory space
  1693.     ExpMgrConfigWriteWord (&(pLynxFWIMData->FWIMRegEntryID), (LogicalAddress) cwCommand,0);
  1694.     
  1695.     // Give back any memory we might have allocated.
  1696.     PoolDeallocate ((LogicalAddress) pLynxFWIMData->baseRxData);
  1697.     PoolDeallocate ((LogicalAddress) pLynxFWIMData->baseTxData);
  1698.     MemDeallocatePhysicallyContiguous ((LogicalAddress) pLynxFWIMData->basePCLData);
  1699.     PoolDeallocate ((LogicalAddress) pLynxFWIMData->baseFWIMDataPtr);    // Needs to be last (obviously...)
  1700.  
  1701.     return (noErr);
  1702. }
  1703.  
  1704.  
  1705. ////////////////////////////////////////////////////////////////////////////////
  1706. //
  1707. // LynxFWIMPollInterrupts
  1708. //
  1709. //   This proc checks for pending interrupts.
  1710. //
  1711. //     2/10/98 I changed this function a lot but don't worry - it never gets called
  1712. //     unless you build with forVMBackingStore turned on. There is no provision whatsoever
  1713. //     in the existing FSL for polling interrupts. -DCB
  1714. //
  1715.  
  1716. static OSStatus    LynxFWIMPollInterrupts(
  1717.     FWIMPollInterruptsParamsPtr    pFWIMPollInterruptsParams)
  1718. {
  1719.     OSStatus                    status = noErr;
  1720.     LynxFWIMDataPtr                pLynxFWIMData;
  1721.     UInt32                        dmaChannelNum;
  1722.     
  1723.     pLynxFWIMData =             (LynxFWIMDataPtr) pFWIMPollInterruptsParams->fwimSpecificData;
  1724.     
  1725.     if( pLynxFWIMData->phyNotPowered )
  1726.         return( accessErr );     // !!! Proper error?
  1727.  
  1728.     // Disable both VM User Code AND Lynx interrupts while we're in here so that 
  1729.     // dispatch interrupts can behave as if it was actually at hardware interrupt
  1730.     // level.
  1731.  
  1732.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  1733.     (*(pLynxFWIMData->interruptDisabler)) (pLynxFWIMData->interruptSetMember,
  1734.                                                 (void *) pLynxFWIMData);    // >>•••••••>> Ints Off
  1735.                                                 
  1736.     // Do we care if we handled an interrupt here? It could be bad if we cleared an int while
  1737.     // interrupt services was running the tree. OTOH this might not be the place to fix it.
  1738.     LynxFWIMDispatchInterrupts(pLynxFWIMData);
  1739.     
  1740.     (*(pLynxFWIMData->interruptEnabler)) (pLynxFWIMData->interruptSetMember,
  1741.                                                 (void *) pLynxFWIMData);    // <<•••••••<< Ints On
  1742.  
  1743.  
  1744.     // LynxFWIMDispatchInterrupts may have enqueued some deferred tasks. If we are polling they
  1745.     // won't get run normally so we have to do it manually here. We don this with ints off
  1746.     // since we might actually be at interrupt level 0 (but in the middle of processing SIHs).
  1747.     
  1748.     for( dmaChannelNum = 0; dmaChannelNum < kNumDMAChannels; dmaChannelNum++ ) {
  1749.         if( pLynxFWIMData->DMAInfo[dmaChannelNum].lynxDTScheduled )
  1750.             LynxFWIMDeferredTaskMultiplexer( pLynxFWIMData, (void *)dmaChannelNum );
  1751.     }
  1752.     
  1753.     if( pLynxFWIMData->busResetDTScheduled ) 
  1754.         LynxFWIMResetDeferredTask(pLynxFWIMData,nil);
  1755.         
  1756.     if( pLynxFWIMData->miscInterruptDTScheduled )
  1757.         LynxFWIMMiscInterruptDeferredTask(pLynxFWIMData,nil);
  1758.                                                         
  1759.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  1760.  
  1761.     return (status);
  1762. }
  1763.  
  1764.  
  1765. ////////////////////////////////////////////////////////////////////////////////
  1766. //
  1767. // LynxFWIMGetRegisterBaseAddress
  1768. //
  1769. //   This proc uses the name registry to find the base address of the registers.
  1770. //
  1771.  
  1772. static OSStatus    LynxFWIMGetRegisterBaseAddress(
  1773.     LynxFWIMDataPtr                pLynxFWIMData)
  1774. {
  1775.     RegEntryIDPtr                pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
  1776.     PCIAssignedAddressPtr        tempFWIMAddressesStorage = nil,
  1777.                                 pFWIMAddresses;
  1778.     Ptr                            pFWIMAddressesEnd;
  1779.     DeviceLogicalAddressPtr        tempFWIMLogicalAddressesStorage = nil,
  1780.                                 pFWIMLogicalAddresses;
  1781.     RegPropertyValueSize        propSize;
  1782.     UInt32                        assignedAddressesSize;
  1783.     Boolean                        done;
  1784.     OSStatus                    status = noErr;
  1785.  
  1786. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMGetRegisterBaseAddress");
  1787.  
  1788.     // Get assigned addresses property.
  1789.     status = RegistryPropertyGetSize
  1790.                 (pFWIMRegEntryID,
  1791.                  (RegPropertyNamePtr) kPCIAssignedAddressProperty,
  1792.                  &propSize);
  1793.  
  1794.     if (status == noErr)
  1795.     {
  1796.         tempFWIMAddressesStorage =
  1797.             (PCIAssignedAddressPtr) PoolAllocateResident (propSize, false);
  1798.         if (tempFWIMAddressesStorage == nil)
  1799.             status = memFullErr;
  1800.         else
  1801.             pFWIMAddresses = tempFWIMAddressesStorage;
  1802.     }
  1803.  
  1804.     if (status == noErr)
  1805.     {
  1806.         status = RegistryPropertyGet
  1807.                     (pFWIMRegEntryID,
  1808.                      (RegPropertyNamePtr) kPCIAssignedAddressProperty,
  1809.                      pFWIMAddresses,
  1810.                      &propSize);
  1811.         assignedAddressesSize = propSize;
  1812.     }
  1813.  
  1814.     // Get logical addresses property.
  1815.     if (status == noErr)
  1816.     {
  1817.         status = RegistryPropertyGetSize
  1818.                     (pFWIMRegEntryID,
  1819.                      (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
  1820.                      &propSize);
  1821.     }
  1822.  
  1823.     if (status == noErr)
  1824.     {
  1825.         tempFWIMLogicalAddressesStorage =
  1826.             (DeviceLogicalAddressPtr) PoolAllocateResident (propSize, false);
  1827.         if (tempFWIMLogicalAddressesStorage == nil)
  1828.             status = memFullErr;
  1829.         else
  1830.             pFWIMLogicalAddresses = tempFWIMLogicalAddressesStorage;
  1831.     }
  1832.  
  1833.     if (status == noErr)
  1834.     {
  1835.         status = RegistryPropertyGet
  1836.                     (pFWIMRegEntryID,
  1837.                      (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
  1838.                      pFWIMLogicalAddresses,
  1839.                      &propSize);
  1840.     }
  1841.  
  1842.     // Scan addresses until we find the one at config space 0x10.
  1843.     if (status == noErr)
  1844.     {
  1845.         pFWIMAddressesEnd = ((Ptr) pFWIMAddresses) + assignedAddressesSize;
  1846.         done = false;
  1847.  
  1848.         while ((((Ptr) pFWIMAddresses) < pFWIMAddressesEnd) && (!done))
  1849.         {
  1850.             if (pFWIMAddresses->registerNumber == 0x10)
  1851.             {
  1852.                 // There is a certain prototype system in which Open Firmware
  1853.                 // doesn't seem to work quite right yet.  If we find that the
  1854.                 // base register is zero, substitute another value for now.
  1855.                 
  1856.                 if (!*pFWIMLogicalAddresses)
  1857.                 {
  1858.                     pLynxFWIMData->pLynxRegisters = (LynxRegistersPtr) pFWIMAddresses->address.lo;
  1859.                     
  1860.                     sprintf (debugStr, "Base register 0, using %08lx", (long) pFWIMAddresses->address.lo);
  1861.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1862.                 }
  1863.                 else
  1864.                 {
  1865.                     pLynxFWIMData->pLynxRegisters = (LynxRegistersPtr) *pFWIMLogicalAddresses;
  1866.                 }
  1867.                 done = true;
  1868.             }
  1869.  
  1870.             pFWIMAddresses++;
  1871.             pFWIMLogicalAddresses++;
  1872.         }
  1873.  
  1874.         if (!done)
  1875.             status = paramErr;
  1876.     }
  1877.  
  1878.     // Deallocate temp storage.
  1879.     if (tempFWIMAddressesStorage != nil)
  1880.         PoolDeallocate ((LogicalAddress) tempFWIMAddressesStorage);
  1881.  
  1882.     if (tempFWIMLogicalAddressesStorage != nil)
  1883.         PoolDeallocate ((LogicalAddress) tempFWIMLogicalAddressesStorage);
  1884.  
  1885.     return (status);
  1886. }
  1887.  
  1888.  
  1889. ////////////////////////////////////////////////////////////////////////////////
  1890. //
  1891. // LynxFWIMInstallInterruptHandler
  1892. //
  1893. //   This proc installs the chip interrupt handler.
  1894. //
  1895.  
  1896. static OSStatus    LynxFWIMInstallInterruptHandler(
  1897.     LynxFWIMDataPtr                pLynxFWIMData)
  1898. {
  1899.     RegEntryIDPtr                pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
  1900.     ISTProperty                    interruptSets;
  1901.     InterruptSetID                interruptSetID;
  1902.     InterruptMemberNumber        interruptMemberNumber;
  1903.     void                        *oldInterruptRefCon;
  1904.     InterruptHandler            oldInterruptHandler;
  1905.     InterruptEnabler            interruptEnabler;
  1906.     InterruptDisabler            interruptDisabler;
  1907.     RegPropertyValueSize        propSize;
  1908.     OSStatus                    status = noErr;
  1909.  
  1910. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMInstallInterruptHandler");
  1911.  
  1912.     // Get our interrupt set from the name registry.
  1913.     propSize = sizeof (ISTProperty);
  1914.     status = RegistryPropertyGet (pFWIMRegEntryID, kISTPropertyName,
  1915.                                   &interruptSets, &propSize);
  1916.     interruptSetID = interruptSets[kISTChipInterruptSource].setID;
  1917.     interruptMemberNumber = interruptSets[kISTChipInterruptSource].member;
  1918.  
  1919.     // Get the interrupt enabler and disabler for our chip interrupt set.
  1920.     if (status == noErr)
  1921.     {
  1922.         status = GetInterruptFunctions
  1923.                     (interruptSetID, interruptMemberNumber,
  1924.                      &oldInterruptRefCon, &oldInterruptHandler,
  1925.                      &interruptEnabler, &interruptDisabler);
  1926.     }
  1927.  
  1928.     // Install the refCon and interrupt handler for our chip interrupt set.
  1929.     if (status == noErr)
  1930.     {
  1931.         status = InstallInterruptFunctions
  1932.                     (interruptSetID, interruptMemberNumber,
  1933.                      pLynxFWIMData, (InterruptHandler) LynxFWIMInterruptHandler,
  1934.                      LynxFWIMInterruptEnabler, LynxFWIMInterruptDisabler);
  1935.     }
  1936.  
  1937.     // Add info to our FWIM Data record.
  1938.     if (status == noErr)
  1939.     {
  1940.         pLynxFWIMData->interruptSetMember.setID = interruptSetID;
  1941.         pLynxFWIMData->interruptSetMember.member = interruptMemberNumber;
  1942.         pLynxFWIMData->oldInterruptRefCon = oldInterruptRefCon;
  1943.         pLynxFWIMData->oldInterruptHandler = oldInterruptHandler;
  1944.         pLynxFWIMData->interruptEnabler = LynxFWIMInterruptEnabler;
  1945.         pLynxFWIMData->interruptOldEnabler = interruptEnabler;
  1946.         pLynxFWIMData->interruptDisabler = LynxFWIMInterruptDisabler;
  1947.         pLynxFWIMData->interruptOldDisabler = interruptDisabler;
  1948.     }
  1949.  
  1950.     return (status);
  1951. }
  1952.  
  1953.  
  1954. ////////////////////////////////////////////////////////////////////////////////
  1955. //
  1956. // LynxFWIMcrc16
  1957. //
  1958. // Compute the CRC-16 value of a block of quadlets.
  1959. // Adapted from Table 23 of IEEE 1212.
  1960. // Takes quadlet pointer and count of quadlets
  1961.  
  1962. static UInt16 LynxFWIMcrc16(
  1963.     UInt32                        *data,
  1964.     UInt32                        count)
  1965. {
  1966.     SInt32                        shift;
  1967.     UInt16                        sum, next = 0;
  1968.     UInt32                        doCount = count, *doData = data;
  1969.     
  1970.     while (doCount--)
  1971.     {
  1972.         for (shift = 28; shift >= 0; shift -= 4)        // 8 times, 4 bits each time
  1973.         {
  1974.             sum = ((next >> 12) ^ (*doData >> shift)) & 0x0f;        // get 4 bits
  1975.             next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;    // apply them
  1976.         }
  1977.         doData++;
  1978.     }
  1979.     
  1980.     return next;
  1981. }
  1982.  
  1983.  
  1984. ////////////////////////////////////////////////////////////////////////////////
  1985. //
  1986. // LynxFWIMControlEEPROM
  1987. //
  1988. // Modify (up to) three EEPROM control bits:  Clock, Data, and Timer.
  1989. // There isn't currently any place we're called without the timer option.
  1990.  
  1991. static void LynxFWIMControlEEPROM(
  1992.     LynxFWIMDataPtr                pLynxFWIMData,
  1993.     UInt32                        clock,
  1994.     UInt32                        data,
  1995.     UInt32                        timer)
  1996. {
  1997.     UInt32                        eepromTemp;
  1998.     
  1999.     eepromTemp = pLynxFWIMData->pLynxRegisters->serialEEPROMControl;
  2000.     SynchronizeIO ();
  2001.     
  2002.     if (clock == kClockHi)
  2003.         eepromTemp |= EndianSwapImm32Bit (kLynxEEPCLK);
  2004.         else eepromTemp &= ~EndianSwapImm32Bit (kLynxEEPCLK);
  2005.  
  2006.     if (data != kNoData)
  2007.     {
  2008.         if (data == kDataHi)
  2009.             eepromTemp |= EndianSwapImm32Bit (kLynxEEPDAT);
  2010.             else eepromTemp &= ~EndianSwapImm32Bit (kLynxEEPDAT);
  2011.     }
  2012.     
  2013.     if (timer == kStartTimer)
  2014.         eepromTemp &= ~EndianSwapImm32Bit (kLynxTIMER_5USEC);
  2015.         else eepromTemp |= EndianSwapImm32Bit (kLynxTIMER_5USEC);
  2016.  
  2017.     pLynxFWIMData->pLynxRegisters->serialEEPROMControl = eepromTemp;
  2018.     SynchronizeIO ();
  2019. }
  2020.  
  2021.  
  2022. ////////////////////////////////////////////////////////////////////////////////
  2023. //
  2024. // LynxFWIMWaitForEEPROM
  2025. //
  2026. // Wait for a previously set timer to expire, then return the EEPROM data bit
  2027.  
  2028. static UInt32 LynxFWIMWaitForEEPROM(
  2029.     LynxFWIMDataPtr                pLynxFWIMData)
  2030. {
  2031.     UInt32                        e = 0;
  2032.         
  2033.     while (!(e & EndianSwapImm32Bit (kLynxTIMER_5USEC)))
  2034.     {
  2035.         e = pLynxFWIMData->pLynxRegisters->serialEEPROMControl;
  2036.         SynchronizeIO ();
  2037.     }
  2038.  
  2039.     return ((e & EndianSwapImm32Bit (kLynxEEPDAT)) != 0);
  2040. }
  2041.  
  2042.  
  2043. ////////////////////////////////////////////////////////////////////////////////
  2044. //
  2045. // LynxFWIMSendEEPROMBit
  2046. //
  2047. // Send one bit to the serial EEPROM.  To do this, assert the data bit, wait for it
  2048. // to be stable, then raise the clock signal for 5us to send the bit, then lower the
  2049. // clock signal.
  2050. // If we do these back to back we might be able to remove the final clock wait.
  2051.  
  2052. static void LynxFWIMSendEEPROMBit(
  2053.     LynxFWIMDataPtr                pLynxFWIMData,
  2054.     UInt32                        bit)
  2055. {
  2056.     int                            dataBit = bit ? kDataHi : kDataLo;
  2057.     
  2058.     // Set initial state
  2059.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, dataBit, kStartTimer);    
  2060.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2061.  
  2062.     // Raise clock to send data
  2063.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, dataBit, kStartTimer);    
  2064.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2065.  
  2066.     // Drop clock to end this bit
  2067.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, dataBit, kStartTimer);    
  2068.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2069. }
  2070.  
  2071.  
  2072. ////////////////////////////////////////////////////////////////////////////////
  2073. //
  2074. // LynxFWIMSendEEPROMByte
  2075. //
  2076. // Send one byte to the EEPROM, MSB first
  2077.  
  2078. static void LynxFWIMSendEEPROMByte(
  2079.     LynxFWIMDataPtr                pLynxFWIMData,
  2080.     UInt8                        sendByte)
  2081. {
  2082.     int                            i; 
  2083.     UInt8                        sendMe = sendByte;
  2084.     
  2085.     for (i = 0; i < 8; i++)
  2086.     {
  2087.         LynxFWIMSendEEPROMBit (pLynxFWIMData, sendMe >> 7);        // Send current MSB
  2088.         sendMe = sendMe << 1;                                    // Rotate next bit into MSB
  2089.     }
  2090. }
  2091.  
  2092.  
  2093. ////////////////////////////////////////////////////////////////////////////////
  2094. //
  2095. // LynxFWIMReadEEPROMBit
  2096. //
  2097.  
  2098. static UInt32 LynxFWIMReadEEPROMBit(
  2099.     LynxFWIMDataPtr                pLynxFWIMData)
  2100. {
  2101.     UInt32                        data;
  2102.     
  2103.     // When reading the data, we have to take the Data line Hi (tristate)
  2104.     // and then see which way the ROM pulls it (high or low)
  2105.     
  2106.     // Set initial state
  2107.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);    
  2108.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2109.  
  2110.     // Now take clock high to receive data
  2111.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kNoData, kStartTimer);
  2112.     data = LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2113.  
  2114.     // set clock low to end this bit
  2115.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kNoData, kStartTimer);
  2116.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2117.     
  2118.     return data;
  2119. }
  2120.  
  2121.  
  2122. ////////////////////////////////////////////////////////////////////////////////
  2123. //
  2124. // LynxFWIMReadEEPROMByte
  2125. //
  2126. // Read one byte from the EEPROM, MSB first
  2127.  
  2128. static UInt8 LynxFWIMReadEEPROMByte(
  2129.     LynxFWIMDataPtr                pLynxFWIMData)
  2130. {
  2131.     int                            i; 
  2132.     UInt8                        readByte = 0;
  2133.     
  2134.     for (i = 0; i < 8; i++)
  2135.         readByte = (readByte << 1) | LynxFWIMReadEEPROMBit (pLynxFWIMData);
  2136.     
  2137.     return readByte;
  2138. }
  2139.  
  2140.  
  2141. ////////////////////////////////////////////////////////////////////////////////
  2142. //
  2143. // LynxFWIMStartEEPROM
  2144. //
  2145. // Send a special "Start" signal to the EEPROM, by taking the data line
  2146. // low while holding the clock line high.
  2147.  
  2148. static void LynxFWIMStartEEPROM (
  2149.     LynxFWIMDataPtr                pLynxFWIMData)
  2150. {
  2151.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);
  2152.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2153.     
  2154.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataHi, kStartTimer);
  2155.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2156.     
  2157.     // While clock is still high, take data low - this signals a "start"
  2158.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataLo, kStartTimer);
  2159.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2160.     
  2161.     // Now take clock low to signal end of "start"
  2162.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataLo, kStartTimer);
  2163.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2164. }
  2165.  
  2166.  
  2167. ////////////////////////////////////////////////////////////////////////////////
  2168. //
  2169. // LynxFWIMStopEEPROM
  2170. //
  2171. // Send a special "Stop" signal to the EEPROM, by taking the data line
  2172. // low while holding the clock line high.
  2173.  
  2174. static void LynxFWIMStopEEPROM (
  2175.     LynxFWIMDataPtr                pLynxFWIMData)
  2176. {
  2177.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataLo, kStartTimer);
  2178.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2179.     
  2180.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataLo, kStartTimer);
  2181.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2182.     
  2183.     // While clock is still high, take data high - this signals a "stop"
  2184.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataHi, kStartTimer);
  2185.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2186.     
  2187.     // Now take clock low to signal end of "stop"
  2188.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);
  2189.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2190. }
  2191.  
  2192.  
  2193. ////////////////////////////////////////////////////////////////////////////////
  2194. //
  2195. // LynxFWIMProcessEEPROM
  2196. //
  2197. // Read data out of the Lynx serial EEPROM, to determine our Unique ID, and
  2198. // some configuration info like how much SRAM we have on board.  This is lots
  2199. // of fun because we have to manually clock the EEPROM by wiggling the clock
  2200. // and data lines around under software control.
  2201. //
  2202. // This takes roughly 30 milliseconds, if the Lynx 5 microsecond timer is accurate
  2203.  
  2204. // still to do:
  2205. // checksum
  2206.  
  2207. static void LynxFWIMProcessEEPROM(
  2208.     LynxFWIMDataPtr                pLynxFWIMData)
  2209. {
  2210.     OSStatus                    status = noErr;
  2211.     UInt32                        eepromState, readQuad, scanQuad, scanKey;
  2212.     SInt32                        scanLen, scanPos, modulePos;
  2213.     LynxEEPROMBasePtr            eepromBase;
  2214.     LynxEEPROMInfoPtr            eepromInfo;
  2215.  
  2216.     eepromBase = (LynxEEPROMBasePtr) pLynxFWIMData->eepromData;
  2217.     eepromInfo = &(pLynxFWIMData->eepromInfo);
  2218.     
  2219.     // Prepare invalid/default values in case something goes wrong
  2220.     
  2221.     pLynxFWIMData->eepromValid = false;
  2222.     modulePos = 0;                                        // Illegal value
  2223.     eepromInfo->module_Vendor_Id = 0xffffffff;            // Legal values are only 24 bits
  2224.     eepromInfo->module_Hardware_Version = 0xffffffff;    // same
  2225.     eepromInfo->node_Hardware_Version = 0xffffffff;        // same
  2226.     eepromInfo->sram_Quads = 0;                            // Assume 0 if key not found
  2227.     eepromInfo->auxRam_Quads = 0;                        // same
  2228.     eepromInfo->aux_Device = 0;                            // same
  2229.     
  2230.     // We can skip all this if the EEPROM is missing or broken:
  2231.     
  2232.     eepromState = EndianSwap32Bit (pLynxFWIMData->pLynxRegisters->serialEEPROMControl);
  2233.     if (eepromState & (kLynxEEPERR | kLynxEEPCHKERR | kLynxNOTPRS))
  2234.         return;
  2235.     
  2236.     // Reset the EEPROM control register & state
  2237.     
  2238.     pLynxFWIMData->pLynxRegisters->serialEEPROMControl =
  2239.         EndianSwapImm32Bit (kLynxEEPENA | kLynxEEPDAT | kLynxTIMER_5USEC);
  2240.     SynchronizeIO ();    
  2241.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  2242.     
  2243.     // First we send a special "start" signal to get the EEPROM's attention.
  2244.  
  2245.     LynxFWIMStartEEPROM (pLynxFWIMData);
  2246.  
  2247.     // In order to do a random read, we pretend to initiate a write.  That
  2248.     // sets the address at which the EEPROM will either read or write.
  2249.     
  2250.     // The WRITE message is formed like this:    10100000  == 0xa0
  2251.     //      Identifies NM24Cxx serial EEPROM ----> 1010   0 <--- 0 indicates WRITE
  2252.     //      Indicates device/block (page) address ---> 000
  2253.  
  2254.     LynxFWIMSendEEPROMByte (pLynxFWIMData, 0xa0);            // WRITE command 01010000
  2255.     LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);                // strobe for Ack
  2256.  
  2257.     LynxFWIMSendEEPROMByte (pLynxFWIMData, 0x00);            // Data address 00000000
  2258.     LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);                // strobe for Ack
  2259.  
  2260.     // Now we're done with the dummy write.  Send another "start" condition.
  2261.  
  2262.     LynxFWIMStartEEPROM (pLynxFWIMData);
  2263.  
  2264.     // READ command is same as WRITE command above, except for last bit.
  2265.  
  2266.     LynxFWIMSendEEPROMByte (pLynxFWIMData, 0xa1);            // READ command 01010001
  2267.     
  2268.     // Read the minimum-sized EEPROM (256 bytes) into memory.
  2269.     
  2270.     for (scanPos = 0; scanPos < kLynxMinEEPROMQuads; scanPos++)
  2271.     {
  2272.         LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);    // ack previous Send/Read
  2273.         
  2274.         readQuad = LynxFWIMReadEEPROMByte (pLynxFWIMData);
  2275.         LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);    // ack
  2276.         
  2277.         readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
  2278.         LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);    // ack
  2279.         
  2280.         readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
  2281.         LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);    // ack
  2282.         
  2283.         readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
  2284.         
  2285.         pLynxFWIMData->eepromData[scanPos] = readQuad;
  2286.     }
  2287.     
  2288.     // Now we are supposed to send a STOP condition.
  2289.  
  2290.     LynxFWIMStopEEPROM (pLynxFWIMData);
  2291.  
  2292.     // We're done with the EEPROM.  Extract some info from what we got.
  2293.     
  2294.     if (eepromBase->crcLen > kLynxMinEEPROMQuads)        // Protect against bogus lengths
  2295.         return;
  2296.  
  2297.     if (eepromBase->crc !=
  2298.         LynxFWIMcrc16 ((UInt32 *) eepromBase->busInfoBlock, (UInt32) eepromBase->crcLen))
  2299.         return;
  2300.     
  2301.     // If we passed CRC on the Bus Info block, declare the EEPROM to be valid.
  2302.     // This means that at least the unique ID is present and passes CRC, which
  2303.     // is all we currently use anyway.
  2304.     
  2305.     pLynxFWIMData->eepromValid = true;
  2306.     BlockCopy ((Ptr) &(eepromBase->busInfoBlock), (Ptr) &(eepromInfo->busInfoBlock), 16);
  2307.     
  2308.     scanLen = eepromBase->romData[0] >> 16;                // Root directory length in quadlets
  2309.  
  2310.     if (scanLen > kLynxMinEEPROMQuads)                    // Protect against bogus lengths
  2311.         return;
  2312.  
  2313.     if ((eepromBase->romData[0] & 0xffff) !=
  2314.         LynxFWIMcrc16 (&(eepromBase->romData[1]), scanLen))
  2315.         return;
  2316.         
  2317.     // Scan the root directory
  2318.     for (scanPos = 1; scanPos <= scanLen; scanPos++)
  2319.     {
  2320.         scanQuad = eepromBase->romData[scanPos];
  2321.         scanKey = scanQuad >> 24;
  2322.         
  2323.         switch (scanKey)
  2324.         {
  2325.             case kLynxEEPROMKeyModuleVendorID:
  2326.                 eepromInfo->module_Vendor_Id = scanQuad & 0xffffff;
  2327.                 break;
  2328.                 
  2329.             case kLynxEEPROMKeyModuleHardwareVersion:
  2330.                 eepromInfo->module_Hardware_Version = scanQuad & 0xffffff;
  2331.                 break;
  2332.                 
  2333.             case kLynxEEPROMKeyNodeHardwareVersion:
  2334.                 eepromInfo->node_Hardware_Version = scanQuad & 0xffffff;
  2335.                 break;
  2336.                 
  2337.             case kLynxEEPROMKeyModuleDependentInfo:
  2338.                 modulePos = scanPos + (scanQuad & 0xffffff);
  2339.                 break;
  2340.                 
  2341.             default: break;
  2342.         }
  2343.     }
  2344.     
  2345.     // Scan the module-dependent directory, if found
  2346.     if (modulePos)
  2347.     {
  2348.         scanLen = eepromBase->romData[modulePos] >> 16;        // Module dep dir length in quadlets
  2349.  
  2350.         if (scanLen > kLynxMinEEPROMQuads)                    // Protect against bogus lengths
  2351.             return;
  2352.  
  2353.         if ((eepromBase->romData[modulePos] & 0xffff) !=
  2354.             LynxFWIMcrc16 (&(eepromBase->romData[modulePos + 1]), scanLen))
  2355.             return;
  2356.         
  2357.         for (scanPos = 1; scanPos <= scanLen; scanPos++)
  2358.         {
  2359.             scanQuad = eepromBase->romData[modulePos + scanPos];
  2360.             scanKey = scanQuad >> 24;
  2361.             
  2362.             switch (scanKey)
  2363.             {
  2364.                 case kLynxEEPROMKeySramQuads:
  2365.                     eepromInfo->sram_Quads = scanQuad & 0xffffff;
  2366.                     break;
  2367.  
  2368.                 case kLynxEEPROMKeyAuxRamQuads:
  2369.                     eepromInfo->auxRam_Quads = scanQuad & 0xffffff;
  2370.                     break;
  2371.                     
  2372.                 case kLynxEEPROMKeyAuxDevice:
  2373.                     eepromInfo->aux_Device = scanQuad & 0xffffff;
  2374.                     break;
  2375.                     
  2376.                 default:
  2377.                     break;
  2378.             }
  2379.         }
  2380.     }
  2381.  
  2382. #if 0    
  2383.     sprintf (debugStr, "EEPROM  Node Vendor ID %06lx   Chip ID %02lx%08lx",
  2384.              (long) eepromInfo->busInfoBlock[2] >> 8,
  2385.              (long) eepromInfo->busInfoBlock[2] & 0xff,
  2386.              (long) eepromInfo->busInfoBlock[3]);
  2387.     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  2388.  
  2389.     sprintf (debugStr, "EEPROM  Mod Vendor ID %06lx   Mod HW Vers %06lx   Node HW Vers %06lx",
  2390.              (long) eepromInfo->module_Vendor_Id,
  2391.              (long) eepromInfo->module_Hardware_Version,
  2392.              (long) eepromInfo->node_Hardware_Version);
  2393.     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  2394.  
  2395.     sprintf (debugStr, "EEPROM  SRAM size %06lx (q)   AUX RAM size %06lx (q)   AUX Device %06lx",
  2396.              (long) eepromInfo->sram_Quads,
  2397.              (long) eepromInfo->auxRam_Quads,
  2398.              (long) eepromInfo->aux_Device);
  2399.     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  2400. #endif
  2401.  
  2402.     return;
  2403. }
  2404.  
  2405.  
  2406. ////////////////////////////////////////////////////////////////////////////////
  2407. //
  2408. // LynxFWIMFullReset
  2409. //
  2410. //   This function flips the SWRST bit to fully reset the Lynx card,
  2411. //   Then re-establishes interrupts, DMA, etc.
  2412. //   This is used both during FWIM Install and any time the card jams up.
  2413. //   As far as I know this does not cause a bus reset.
  2414. //
  2415.  
  2416. static void    LynxFWIMFullReset(void)
  2417. {
  2418.     LynxFWIMDataPtr                pLynxFWIMData = HACKdata;
  2419.     LynxRegistersPtr            pLynxRegs;
  2420.     UInt32                        nodeAddress;
  2421.     OSStatus                    status = noErr;
  2422.     static UInt32                firstTime = 1;
  2423.     UInt32                        physicalID;
  2424.     UInt32                        oldNodeID;
  2425.     UInt8                        phyExtended;
  2426.     UInt8                        phyPorts;
  2427.  
  2428. //    FWDebugStr ((ConstStr255Param) "\p(Lynx) LynxFWIMFullReset");
  2429.  
  2430. // Do we need to cancel any timers?!?
  2431.  
  2432.     pLynxRegs = pLynxFWIMData->pLynxRegisters;    
  2433.  
  2434.     if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  2435.             (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  2436.             (UInt32 *) &oldNodeID ))
  2437.         return;
  2438.     
  2439.     oldNodeID = EndianSwap32Bit (oldNodeID);
  2440.     
  2441.     // Reset everything:
  2442.     pLynxRegs->miscControl = EndianSwapImm32Bit (kLynxSWRST);
  2443.     SynchronizeIO ();
  2444.     if (pLynxRegs->miscControl & EndianSwapImm32Bit (kLynxSWRST))
  2445.         FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Should have waited for SWRST");
  2446.     
  2447.     // Lynx errata for pre-REV A advises this:
  2448.     // Lynx errata for     REV A advises NOT to do this:
  2449.     //pLynxRegs->miscControl = EndianSwapImm32Bit (kLynxENA_POST_WR | kLynxENA_SLV_BURST);
  2450.     SynchronizeIO ();
  2451.  
  2452.     if (firstTime)
  2453.         LynxFWIMProcessEEPROM (pLynxFWIMData);
  2454.     
  2455.     // Set up the FIFOs.
  2456.     LynxFWIMSetupFIFOs (pLynxFWIMData);
  2457.  
  2458.     // Set up DMA for packet reception (Turns on comparators)
  2459.     
  2460.     pLynxFWIMData->pNextAsyncPCL = nil;    // Make sure we start processing PCLs from the beginning.
  2461.  
  2462.     LynxFWIMPrepareAsyncDMA (pLynxFWIMData, pLynxFWIMData->asyncRxDMA);
  2463.             
  2464.     // Some information about the DMA comparators
  2465.     // (The Lynx 0.10 spec is very confusing)
  2466.     
  2467.     // This makes all self-ID, async, and isoch arrive on one DMA channel (0)
  2468.     // including async packets not directed to our node/bus ID:
  2469.     //   Set all enables and values to 0, except for 0x0B0C: RCV_SELF_ID_EN | EN_CH_COMPARE
  2470.     
  2471.     // For the same as above on channel 0, except with all isoch going to channel
  2472.     // 1 instead, set 0x0B04 to 0x000000A0 ('Async tcode encoding ("normal") -> GRF')
  2473.     // Also turn on EN_CH_COMPARE for channel 1
  2474.     
  2475.     // Same as previous, but send async that isn't for our own node onto channel 1
  2476.     // along with all the isochronous packets:
  2477.     // set 0x0B0C to RCV_SELF_ID_EN | EN_CH_COMPARE | DEST_ID_SEL (00001)
  2478.     
  2479.     // Here's what we actually do - all of the above, plus, restrict channel 1 to
  2480.     // isoch only, so we no longer receive async packets that aren't for our node.
  2481.     // Set 0x0B14 to 0x00000090 ('Iso tcode encoding ("normal") -> GRF')
  2482.  
  2483.     // This controls retries ONLY for busy acknowledge, not data errors or no-ack
  2484.     // cases.  Busy ack means the other node really is there, but just can't handle
  2485.     // our packet right now (possibly because they experienced a FIFO overflow).
  2486.     // It's probably good to try a bunch of times, because busy is a rare case, and
  2487.     // we always expect to get through eventually.
  2488.     
  2489.     // Mark up to 32 retries, 16 cycles apart (1/15 second max delay)
  2490.     if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  2491.             (UInt32 *) &pLynxRegs->retryCountInterval,
  2492.             (UInt32) EndianSwapImm32Bit (0x00001020) ))
  2493.         return;
  2494.     
  2495.     // Enable Receiver and Transmitter
  2496.     LynxFWIMSetLinkControl ( pLynxFWIMData,
  2497.                             EndianSwapImm32Bit(
  2498.                             kLynxTX_ISO_EN |
  2499.                             kLynxRX_ISO_EN |
  2500.                             kLynxTX_ASYNC_EN |
  2501.                             kLynxRX_ASYNC_EN |
  2502.                             kLynxRCV_COMP_VALID));
  2503.     
  2504.     if (firstTime)
  2505.     {
  2506.         // Find out what kind of PHY we have. This is done by looking at the Extended field
  2507.         // in the new PHY register set definition. If it is all 1's (0x07) then we have the
  2508.         // extended register file. If anything is zero we don't.
  2509.         // Note that this field overlaps partially with the SPD field in the old PHY register
  2510.         // file but that's OK since it also overlaps with the REV field which will always
  2511.         // be zero.
  2512.         
  2513.         phyExtended = LynxFWIMReadPhyRegister(pLynxFWIMData, kLynxExtPhyExtAddress);
  2514.         phyExtended = (phyExtended & kLynxExtPhyExt) >> kLynxExtPhyExtPhase;
  2515.         
  2516.         if( phyExtended == 0x07 ){ // Will never be true with the old PHY,
  2517.             pLynxFWIMData->extendedPhyRegs = true;
  2518.             pLynxFWIMData->receiveLocalSelfID = true;
  2519.             
  2520.             // Find out how many ports we have
  2521.             phyPorts = LynxFWIMReadPhyRegister(pLynxFWIMData, kLynxExtPhyNPAddress);
  2522.             phyPorts = (phyPorts & kLynxExtPhyNP) >> kLynxExtPhyNPPhase;
  2523.         }
  2524.         else {
  2525.             pLynxFWIMData->extendedPhyRegs = false;
  2526.  
  2527. #ifdef FujiPHY
  2528. #if FujiPHY
  2529.             // Some cards have a FujiFilm MD8404 PHY.  This PHY does not claim to
  2530.             // have extended registers.  But it *does* send the local self-ID.
  2531.             pLynxFWIMData->receiveLocalSelfID = true;
  2532. #else
  2533.             pLynxFWIMData->receiveLocalSelfID = false;
  2534. #endif
  2535. #endif
  2536.  
  2537. #ifndef FujiPHY
  2538.             pLynxFWIMData->receiveLocalSelfID = false;
  2539. #endif
  2540.  
  2541.             // Find out how many ports we have
  2542.             phyPorts = LynxFWIMReadPhyRegister(pLynxFWIMData, kLynxPhyNPAddress);
  2543.             phyPorts = (phyPorts & kLynxPhyNP) >> kLynxPhyNPPhase;
  2544.         }
  2545.             
  2546.         pLynxFWIMData->numPHYPorts = phyPorts;
  2547.  
  2548.         // Get physical ID.
  2549.         NoPhyReset = 1;
  2550.         physicalID = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyPhysicalIDAddress);
  2551.         NoPhyReset = 0;
  2552.         physicalID = (physicalID & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
  2553.     
  2554.         // Set our bus number to default 0x3FF.
  2555.         //zzz how will we determine correct bus number.
  2556.     
  2557.         if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  2558.                 (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  2559.                 (UInt32 *) &nodeAddress ))
  2560.             return;
  2561.         
  2562.         nodeAddress = EndianSwap32Bit (nodeAddress);
  2563.  
  2564.         nodeAddress =    (nodeAddress & (~kLynxBUS_ID)) |
  2565.                         ((0x3FF << kLynxBUS_IDPhase) & kLynxBUS_ID);
  2566.         nodeAddress =    (nodeAddress & (~kLynxNODE_ID)) |
  2567.                         ((physicalID << kLynxNODE_IDPhase) & kLynxNODE_ID);
  2568.  
  2569.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  2570.                 (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  2571.                 (UInt32) EndianSwap32Bit (nodeAddress) ))
  2572.             return;
  2573.     }
  2574.     else
  2575.     {
  2576.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  2577.                 (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  2578.                 (UInt32) EndianSwap32Bit (nodeAddress) ))
  2579.             return;
  2580.     }
  2581.     
  2582. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Enable interrupts");
  2583.  
  2584.     if (firstTime)
  2585.     {
  2586.         // Enable chip interrupts.
  2587.         if (status == noErr)
  2588.         {
  2589.             (*(pLynxFWIMData->interruptOldEnabler)) (pLynxFWIMData->interruptSetMember,
  2590.                                                 pLynxFWIMData->oldInterruptRefCon);
  2591.                                         
  2592.         }
  2593.     }
  2594.  
  2595.     // Enable interrupts for bus resets, phy registers, and DMA PCL ints
  2596.     {
  2597.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  2598.                 (UInt32 *) &pLynxRegs->linkInterruptEnable,
  2599.                 (UInt32) EndianSwapImm32Bit (kLynxLINK_INT |
  2600.                                     kLynxPHY_BUSRESET |
  2601.                                     kLynxPHY_REG_RCVD)))
  2602.             return;
  2603.  
  2604.         // Enable additional interrupts only if we are running FireBug.
  2605.         // Interrupts will be reported to FireBug.
  2606.         // Normally there's nothing we can do about these interrupts.
  2607.         
  2608. #ifdef LynxFireBug
  2609.         if( LynxFWIMSetRegisterBits( pLynxFWIMData,
  2610.             (UInt32 *) &pLynxRegs->linkInterruptEnable,
  2611.             (UInt32) EndianSwapImm32Bit (kLynxPHY_TIME_OUT |
  2612.                                 kLynxIT_STUCK |
  2613.                                 kLynxAT_STUCK |
  2614.                                 kLynxTC_ERR |
  2615.                                 kLynxITF_UNDER_FLOW |
  2616.                                 kLynxATF_UNDER_FLOW |
  2617.                                 kLynxIARB_FAILED)))
  2618.             return;
  2619.         
  2620.         // Note:  Checking for CYC_LOST is tricky.  We'll get 8000/second
  2621.         // unless we're cycle master or someone else is.  There can be
  2622.         // periods with no cycle master, and, sending out the message about
  2623.         // the interrupts repeatedly could prevent us from establishing a
  2624.         // new cycle master.
  2625.         
  2626.         // Checking for CYC_ARB_FAILED is also tricky.  It seems to indicate
  2627.         // that the bus was not idle when the cycle timer rolled over.  This
  2628.         // means that the cycle start packet was delayed, not lost.  That may
  2629.         // not be of great interest.
  2630.         
  2631.         // Header Error interrupt is broken on revA parts
  2632.         
  2633.         if ((pLynxRegs->configClassRevID >> 24) == 0) {
  2634.         
  2635.             if( LynxFWIMSetRegisterBits( pLynxFWIMData,
  2636.                     (UInt32 *) &pLynxRegs->linkInterruptEnable,
  2637.                     (UInt32) EndianSwapImm32Bit (kLynxHDR_ERR)))
  2638.                 return;
  2639.         
  2640.         }
  2641.  
  2642. #endif
  2643.         // Enable appropriate Interrupts
  2644.         LynxFWIMInterruptSetup( pLynxFWIMData );
  2645.  
  2646.     }
  2647.     
  2648.     // Enable Cycle Timer.
  2649.     {
  2650.         LynxFWIMSetLinkControlBits
  2651.             (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCTIMEREN));
  2652.     }
  2653.  
  2654. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Survived!");
  2655.  
  2656.     firstTime = 0;
  2657. }
  2658.  
  2659. ////////////////////////////////////////////////////////////////////////////////
  2660. //
  2661. // LynxFWIMDisableComparators
  2662. //
  2663. //   Disables the comparators for the various (up to 3) rx channels. Uses the
  2664. //   safe register access routines.
  2665. //
  2666. static OSStatus LynxFWIMDisableComparators (
  2667.     LynxFWIMDataPtr                pLynxFWIMData )
  2668.  
  2669. {
  2670.     LynxRegistersPtr            pLynxRegs;
  2671.     OSStatus                    status = noErr;
  2672.  
  2673.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2674.     
  2675.     
  2676.     status = LynxFWIMClearRegisterBits( pLynxFWIMData,
  2677.                 (UInt32 *) &pLynxRegs->dmaComparator[pLynxFWIMData->asyncRxDMA].mask1,
  2678.                 (UInt32) EndianSwapImm32Bit (kLynxEN_CH_COMPARE));
  2679.     SynchronizeIO ();
  2680.     
  2681.     return( status );
  2682. }
  2683.  
  2684. ////////////////////////////////////////////////////////////////////////////////
  2685. //
  2686. // LynxFWIMEnableComparators
  2687. //
  2688. //   Enables the comparators for the various (up to 3) rx channels.
  2689. //
  2690. static OSStatus LynxFWIMEnableComparators (
  2691.     LynxFWIMDataPtr                pLynxFWIMData )
  2692. {
  2693.     LynxRegistersPtr            pLynxRegs;
  2694.     OSStatus                    status = noErr;
  2695.  
  2696.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2697.  
  2698.     status = LynxFWIMSetRegisterBits( pLynxFWIMData,
  2699.                 (UInt32 *) &pLynxRegs->dmaComparator[pLynxFWIMData->asyncRxDMA].mask1,
  2700.                 (UInt32) EndianSwapImm32Bit (kLynxEN_CH_COMPARE));
  2701.     SynchronizeIO ();
  2702.         
  2703.     return( status );
  2704. }
  2705.  
  2706.  
  2707. ////////////////////////////////////////////////////////////////////////////////
  2708. //
  2709. // LynxFWIMInterruptSetup
  2710. //
  2711. //   Figures out which interrupts to enable.
  2712. //
  2713.  
  2714. void LynxFWIMInterruptSetup(
  2715.     LynxFWIMDataPtr                pLynxFWIMData)
  2716. {
  2717.  
  2718.     UInt32                        dmaChannel;
  2719.     LynxRegistersPtr            pLynxRegs;
  2720.  
  2721.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2722.  
  2723.     // Enable PCL interrupts for any channel doing async receive or isochronous anything
  2724.     pLynxFWIMData->interruptMask = kLynxP1394_INT;
  2725.     for( dmaChannel = 0; dmaChannel < kNumDMAChannels; dmaChannel++ ) {
  2726.         
  2727.         switch( pLynxFWIMData->DMAInfo[dmaChannel].channelType ) {
  2728.         
  2729.         case kAsyncRcv:
  2730.         case kIsochRcv:
  2731.         case kIsochXmit:
  2732.             switch( dmaChannel ) {
  2733.             
  2734.             case 0:
  2735.                 pLynxFWIMData->interruptMask |= kLynxDMA0_PCL;
  2736.                 break;
  2737.             case 1:
  2738.                 pLynxFWIMData->interruptMask |= kLynxDMA1_PCL;
  2739.                 break;
  2740.             case 2:
  2741.                 pLynxFWIMData->interruptMask |= kLynxDMA2_PCL;
  2742.                 break;
  2743.             case 3:
  2744.                 pLynxFWIMData->interruptMask |= kLynxDMA3_PCL;
  2745.                 break;
  2746.             case 4:
  2747.                 pLynxFWIMData->interruptMask |= kLynxDMA4_PCL;
  2748.                 break;
  2749.             
  2750.             }
  2751.             break;
  2752.  
  2753.         default:
  2754.             break;
  2755.         }
  2756.     }
  2757.  
  2758.     if( !pLynxFWIMData->intsDisabledCount && !pLynxFWIMData->phyNotPowered ) {
  2759.         pLynxRegs->pciInterruptEnable =
  2760.             EndianSwap32Bit ( pLynxFWIMData->interruptMask );
  2761.         SynchronizeIO ();
  2762.     }
  2763.  
  2764. }
  2765.  
  2766. ////////////////////////////////////////////////////////////////////////////////
  2767. //
  2768. // LynxFWIMExceptionHandler
  2769. //
  2770. //   This proc handles exceptions.
  2771. //
  2772.  
  2773. static OSStatus    LynxFWIMExceptionHandler(
  2774.     ExceptionInformationPowerPC    *theException)
  2775. {
  2776.     OSStatus                    status = noErr;
  2777.  
  2778.     FWDebugStr ((ConstStr255Param) "\pLynxFWIMExceptionHandler");
  2779.  
  2780.     return (status);
  2781. }
  2782.  
  2783.  
  2784. ////////////////////////////////////////////////////////////////////////////////
  2785. //
  2786. // LynxFWIMInterruptHandler
  2787. //
  2788. //   This is the handler proc for chip interrupts.
  2789. //
  2790.  
  2791. static InterruptMemberNumber    LynxFWIMInterruptHandler(
  2792.     InterruptSetMember            interruptSetMember,
  2793.     void                        *interruptRefCon,
  2794.     UInt32                        interruptCount)
  2795. {
  2796.     OSStatus                    status;
  2797.     
  2798.     LynxFWIMDisableVMUserCode((LynxFWIMDataPtr) interruptRefCon);
  2799.  
  2800.     if( LynxFWIMDispatchInterrupts ((LynxFWIMDataPtr) interruptRefCon) )
  2801.         status = kIsrIsComplete;
  2802.     else
  2803.         status = kIsrIsNotComplete;
  2804.  
  2805.     LynxFWIMEnableVMUserCode((LynxFWIMDataPtr) interruptRefCon);
  2806.  
  2807.     return (status);
  2808. }
  2809.  
  2810.  
  2811. ////////////////////////////////////////////////////////////////////////////////
  2812. //
  2813. // LynxFWIMInterruptEnabler
  2814. //
  2815. //   Enables interrupts. We have our own functions for this because if a card is
  2816. //     behind a bridge you can't be guaranteed that the default functions will always
  2817. //      do the right thing. Also this one keeps a count of how many times we've disabled
  2818. //     interrupts and won't enable them until the count is zero.
  2819. //
  2820.  
  2821. static void    LynxFWIMInterruptEnabler(
  2822.     InterruptSetMember            interruptSetMember,
  2823.     void                        *interruptRefCon )
  2824. {
  2825.     LynxFWIMDataPtr                pLynxFWIMData;
  2826.     LynxRegistersPtr            pLynxRegs;
  2827.     
  2828.     pLynxFWIMData = (LynxFWIMDataPtr) interruptRefCon;
  2829.  
  2830.     // Get our register base address.
  2831.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2832.  
  2833.     DecrementAtomic( &pLynxFWIMData->intsDisabledCount );
  2834.     
  2835.     if( !pLynxFWIMData->intsDisabledCount ) {
  2836.         (*(pLynxFWIMData->interruptOldEnabler)) (pLynxFWIMData->interruptSetMember,
  2837.                                         pLynxFWIMData->oldInterruptRefCon);
  2838.         pLynxRegs->pciInterruptEnable = EndianSwap32Bit ( pLynxFWIMData->interruptMask ); // LynxFWIMInterruptSetup keeps track of which bit to enable
  2839.         
  2840.     }
  2841.  
  2842. }
  2843.  
  2844. ////////////////////////////////////////////////////////////////////////////////
  2845. //
  2846. // LynxFWIMInterruptDisabler
  2847. //
  2848. //   Disables interrupts. We have our own functions for this because if a card is
  2849. //     behind a bridge you can't be guaranteed that the default functions will always
  2850. //      do the right thing. Also this one keeps a count of how many times we've disabled
  2851. //     interrupts and won't enable them until the count is zero.
  2852. //
  2853.  
  2854. static InterruptSourceState    LynxFWIMInterruptDisabler(
  2855.     InterruptSetMember            interruptSetMember,
  2856.     void                        *interruptRefCon )
  2857. {
  2858.     LynxFWIMDataPtr                pLynxFWIMData;
  2859.     LynxRegistersPtr            pLynxRegs;
  2860.     SInt32                        previousState;                        
  2861.     
  2862.     pLynxFWIMData = (LynxFWIMDataPtr) interruptRefCon;
  2863.  
  2864.     // Get our register base address.
  2865.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2866.  
  2867.     previousState = IncrementAtomic( &pLynxFWIMData->intsDisabledCount );
  2868.     
  2869.     pLynxRegs->pciInterruptEnable = 0;    // LynxFWIMInterruptSetup keeps track of which bit to enable
  2870.     
  2871.     if( !previousState ) 
  2872.         (*(pLynxFWIMData->interruptOldEnabler)) (pLynxFWIMData->interruptSetMember,
  2873.                                         pLynxFWIMData->oldInterruptRefCon);
  2874.                                         
  2875.     if( previousState )
  2876.         return( kSourceWasDisabled);
  2877.     else
  2878.         return( kSourceWasEnabled);
  2879.     
  2880. }
  2881.  
  2882.  
  2883.  
  2884. ////////////////////////////////////////////////////////////////////////////////
  2885. //
  2886. // LynxFWIMDispatchInterrupts
  2887. //
  2888. //   This proc dispatches any pending interrupts.
  2889. //
  2890.  
  2891. static Boolean    LynxFWIMDispatchInterrupts(
  2892.     LynxFWIMDataPtr                pLynxFWIMData)
  2893. {
  2894.     LynxRegistersPtr            pLynxRegs;
  2895.     UInt32                        interruptStatus, interruptStatusLittleEndian;
  2896.  
  2897.     // Get our register base address.
  2898.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2899.  
  2900.     // Read PCI interrupt status register.
  2901.     interruptStatusLittleEndian = pLynxRegs->pciInterruptStatus;
  2902.     interruptStatus = EndianSwap32Bit (interruptStatusLittleEndian);
  2903.  
  2904.     // Note - there are lots of kinds of ints other than 1394 and DMA
  2905.     // that can happen.  We'll probably want to catch some of them.
  2906.     
  2907. #if FW_DEBUG_BUILD    
  2908.     
  2909.     pLynxFWIMData->interruptValues[0] = pLynxFWIMData->interruptValues[1];
  2910.     pLynxFWIMData->interruptValues[1] = pLynxFWIMData->interruptValues[2];
  2911.     pLynxFWIMData->interruptValues[2] = pLynxFWIMData->interruptValues[3];
  2912.     pLynxFWIMData->interruptValues[3] = interruptStatus;
  2913.  
  2914. #endif
  2915.     
  2916.     // Check for each type of supported interrupt.
  2917.     if (interruptStatus & kLynxINT_PEND)
  2918.     {
  2919.         // Check for link interrupt.  Could be a reset, must do that first
  2920.         if (interruptStatus & kLynxP1394_INT)
  2921.             LynxFWIMHandleLinkInterrupt (pLynxFWIMData);
  2922.  
  2923.         // Check for DMA 0 PCL interrupt.
  2924.         if (interruptStatus & (kLynxDMA0_PCL | kLynxDMA0_HLT)) 
  2925.             LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 0);
  2926.                         
  2927.         // Check for DMA 1 PCL interrupt.
  2928.         if (interruptStatus & (kLynxDMA1_PCL | kLynxDMA1_HLT))
  2929.             LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 1);
  2930.                         
  2931.         // Check for DMA 2 PCL interrupt.
  2932.         if (interruptStatus & (kLynxDMA2_PCL | kLynxDMA2_HLT))
  2933.             LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 2);
  2934.                         
  2935.         // Check for DMA 3 PCL interrupt.
  2936.         if (interruptStatus & (kLynxDMA3_PCL | kLynxDMA3_HLT))
  2937.             LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 3);
  2938.                         
  2939.         // Check for DMA 4 PCL interrupt.
  2940.         if (interruptStatus & (kLynxDMA4_PCL | kLynxDMA4_HLT))
  2941.             LynxFWIMHandleDMAInterrupt (pLynxFWIMData, 4);
  2942.                         
  2943.     }
  2944.  
  2945.     // Clear the interrupts. (!!! does this inadvertantly clear interrupts which we have not enabled?)
  2946.     // !!! should we only clear those interrupts we know are enabled or do we just not care about the 
  2947.     // other possible interrupts since we aren't using them anyway?
  2948.     
  2949.     pLynxRegs->pciInterruptStatus = interruptStatusLittleEndian;
  2950.     SynchronizeIO ();
  2951.  
  2952.     // Did we actually see an interrupt from our hardware? We only count those that are enabled and
  2953.     // might actually cause an interrupt. This is still wrong because if we are doing interrupt polling
  2954.     // we might have cleared the interrupt while interrupt services was walking the tree. If we report 
  2955.     // that we didn't handle the interrupt bad things (like a hang) can happen!!!
  2956.     
  2957.     if( interruptStatus & pLynxFWIMData->interruptMask )
  2958.         return (true);
  2959.     else
  2960.         return (false);
  2961. }
  2962.  
  2963.  
  2964. ////////////////////////////////////////////////////////////////////////////////
  2965. //
  2966. // LynxFWIMHandleDMAInterrupt
  2967. //
  2968. //   This proc handles interrupts sent by PCLs. What kind of processing to do is
  2969. //      left to the deferred task which figures this out by indexing into the DMAInfo
  2970. //     structure with the dmaChannel parameter
  2971. //
  2972.  
  2973. static void LynxFWIMHandleDMAInterrupt(
  2974.     LynxFWIMDataPtr                pLynxFWIMData,
  2975.     UInt32                        dmaChannel )
  2976. {
  2977.     OSStatus                    status = noErr;
  2978.  
  2979.     if (!(pLynxFWIMData->DMAInfo[dmaChannel].lynxDTScheduled))
  2980.     {
  2981.         status = FWScheduleDeferredTask (pLynxFWIMData->DMAInfo[dmaChannel].lynxDT, (void *)dmaChannel);
  2982.  
  2983.         if (status == noErr)
  2984.             pLynxFWIMData->DMAInfo[dmaChannel].lynxDTScheduled = true;
  2985.     }
  2986. }
  2987.  
  2988. ////////////////////////////////////////////////////////////////////////////////
  2989. //
  2990. // LynxFWIMHandleLinkInterrupt
  2991. //
  2992. //   This proc handles 1394-specific interrupts (bus reset, GRF overflow).
  2993. //
  2994.  
  2995. static UInt32 flushCount = 0;
  2996.  
  2997. static void LynxFWIMHandleLinkInterrupt(
  2998.     LynxFWIMDataPtr                pLynxFWIMData)
  2999. {
  3000.     LynxRegistersPtr            pLynxRegs;
  3001.     UInt32                        interrupt, interruptLittleEndian, mask;
  3002.     UInt32                        handled = 0;
  3003.  
  3004.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3005.  
  3006.     if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3007.             (UInt32 *) &pLynxRegs->linkInterruptStatus,
  3008.             (UInt32 *) &interruptLittleEndian ) )
  3009.         return;
  3010.  
  3011.     interrupt = EndianSwapImm32Bit (interruptLittleEndian);
  3012.  
  3013.     // Mask out disabled interrupts.
  3014.     if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3015.             (UInt32 *) &pLynxRegs->linkInterruptEnable,
  3016.             (UInt32 *) &mask ))
  3017.         return;
  3018.     mask = EndianSwap32Bit (mask) | kLynxLINK_INT;
  3019.     interrupt &= mask;
  3020.  
  3021.     // Check for each type of supported interrupt.
  3022.     if (interrupt & kLynxLINK_INT)
  3023.     {
  3024.         // Check for reset interrupt.
  3025.         if (interrupt & kLynxPHY_BUSRESET)
  3026.         {
  3027.             LynxFWIMHandleResetInterrupt (pLynxFWIMData);
  3028.         }
  3029.                         
  3030.         // Check for phy register interrupt.
  3031.         if (interrupt & kLynxPHY_REG_RCVD)
  3032.         {
  3033.             LynxFWIMHandlePhyRegRcvdInterrupt (pLynxFWIMData,interrupt);
  3034.         }
  3035.                         
  3036.         // Check for GRF overflow interrupt.
  3037.         if ((interrupt & kLynxGRF_OVER_FLOW) ||
  3038.             (interrupt & kLynxSNTRJ))
  3039.         {
  3040. // This needs work, and its own function.  Redoing the DMA prep may take too long, too.
  3041. //zzz do we really need to do anything with GRF overflow.
  3042. //zzz flushing the GRF seems to only cause problems.
  3043.             FWDebugStr ((ConstStr255Param) "\pLynxFWIMHandleLinkInterrupt - GRF OVERFLOW ###");
  3044.         }
  3045.  
  3046. #ifdef LynxFireBug
  3047.         if (!(interrupt & kLynxPHY_BUSRESET))
  3048.         {
  3049.             LynxFWIMHandleMiscInterrupt (pLynxFWIMData);
  3050.         }
  3051. #endif
  3052.     }
  3053.  
  3054.     // Clear the interrupts.
  3055.     LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  3056.         (UInt32 *) &pLynxRegs->linkInterruptStatus,
  3057.         (UInt32) interruptLittleEndian );
  3058. }
  3059.  
  3060.  
  3061. ////////////////////////////////////////////////////////////////////////////////
  3062. //
  3063. // LynxFWIMHandleResetInterrupt
  3064. //
  3065. //   This proc handles bus reset interrupts.
  3066. //zzz must be able to handle two resets happening before we process one.
  3067. //
  3068.  
  3069. static void LynxFWIMHandleResetInterrupt(
  3070.     LynxFWIMDataPtr                pLynxFWIMData)
  3071. {
  3072.     LynxRegistersPtr            pLynxRegs;
  3073.     OSStatus                    status = noErr;
  3074.  
  3075.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3076.         
  3077.     // When we get a reset interrupt, the async transmitter and receiver have been disabled.
  3078.     // We can't accept (or ack) packets until we know our new node number, and that won't
  3079.     // happen until about 150 microseconds from now, when we get the PHY REG RCVD interrupt.
  3080.     // We can't enable the receiver until we know this number, because if we do, we'll send
  3081.     // acks to packets directed at some other node (if our node ID changed).
  3082.     
  3083.     // We used to disable the async comparator here but that caused problems if the main
  3084.     // receive channel wasn't DMA channel 0 and we were doing some sort of specialized receive
  3085.     // on channel 1. The self-ids would come in but we would never get the end of packet token
  3086.     // and the PCL would get marked as bad.
  3087.     
  3088.     // So...
  3089.     // In order to prevent acking a packet that isn't ours we leave the receiver disabled until
  3090.     // we get the PHY REG RCVD interrupt. When we do we mask the comparator then and enable the
  3091.     // async receiver. If we then see a pending reset interrupt or if one was pending at the time
  3092.     // we handled this interrupt (ie they were simultaneous) then we disable the async comparator
  3093.     // assuming that we'll get another PHY REG RCVD with the valid node id. This assumes that if
  3094.     // a reset interrupt preceeds a PHY REG RCVD interrupt it will in fact prevent the PHY REG RCVD
  3095.     // interrupt until the PHY gets a valid node ID.
  3096.  
  3097.     // Invalidate bus generation number.
  3098.     pLynxFWIMData->generationValid = false;
  3099.  
  3100.     // We know for sure the Node ID is false.
  3101.     pLynxFWIMData->phyNodeThoughtValid = false;
  3102.  
  3103.     // If we were expecting a reset, because we just rewrote the CSR ROM, do two things.
  3104.     if (pLynxFWIMData->csrROMUpdateClearWhenDone)
  3105.     {
  3106.         // OpenHCI only:  Flip the Config ROM Mapping Register to a new value:
  3107.         
  3108.         // Everyone:  Tell FSL that a reset has come in to complete the process:
  3109.         *(pLynxFWIMData->csrROMUpdateClearWhenDone) = 0;
  3110.         SynchronizeIO ();
  3111.         
  3112.         pLynxFWIMData->csrROMUpdateClearWhenDone = 0;        // Don't do it twice
  3113.         
  3114.     }
  3115.     
  3116.     // Process the reset.
  3117.     status = FWProcessBusReset (pLynxFWIMData->fwimID);
  3118.  
  3119.     // Schedule deferred task to handle reset.
  3120.     if (!(pLynxFWIMData->busResetDTScheduled))
  3121.     {
  3122.         status = FWScheduleDeferredTask (pLynxFWIMData->busResetDeferredTaskID, nil);
  3123.  
  3124.         if (status == noErr)
  3125.             pLynxFWIMData->busResetDTScheduled = true;
  3126.     }
  3127. }
  3128.  
  3129.  
  3130. ////////////////////////////////////////////////////////////////////////////////
  3131. //
  3132. // LynxFWIMHandlePhyRegRcvdInterrupt
  3133. //
  3134. //   This proc handles phy register receive interrupts.
  3135. //   Any time we get register 0, load the nodeID register.
  3136. //   This only really matters after a bus reset, but is harmless at other times.
  3137. //
  3138.  
  3139. static void LynxFWIMHandlePhyRegRcvdInterrupt(
  3140.     LynxFWIMDataPtr                pLynxFWIMData,
  3141.     UInt32                        interrupt)
  3142. {
  3143.     LynxRegistersPtr            pLynxRegs;
  3144.     AbsoluteTime                timeoutAbsolute;
  3145.     AbsoluteTime                timeRemaining;
  3146.     OSStatus                    status = noErr;
  3147.     UInt32                        phyData, busNodeID, newNodeID;
  3148.     UInt32                        interruptLittleEndian;
  3149.     UInt32                        linkData;
  3150.  
  3151.     // This happens about 150 microseconds after a bus reset, when the PHY sends
  3152.     // register zero automatically.  That's when we learn our new node ID, so we
  3153.     // interrupt to this function, and load that ID into register 0xF00.  Now we
  3154.     // can send acks for packets directed at us, so we turn the comparator back
  3155.     // on and try to start receiving packets.
  3156.     
  3157.     // If there has been another bus reset after the PHY interrupt but before we
  3158.     // get here, then we'll load a stale value but we can detect this by looking at the 
  3159.     // link interrupt status register and also its contents when we handled the interrupt
  3160.     // in the primary interrupt handler. If we see a reset we can disable the receiver 
  3161.     // again since we know we'll get back here again soon.
  3162.  
  3163.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3164.  
  3165.     if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3166.             (UInt32 *) &pLynxRegs->phyControl,
  3167.             (UInt32 *) &phyData ))
  3168.         return;
  3169.  
  3170.     phyData = EndianSwap32Bit (phyData);
  3171.     
  3172.     if (((phyData & kLynxPHY_REGRD_ADR) >> kLynxPHY_REGRD_ADRPhase) == 0)
  3173.     {
  3174.  
  3175.         // Disable comparator
  3176.         LynxFWIMDisableComparators(pLynxFWIMData);
  3177.         
  3178.         phyData = (phyData & kLynxPHY_REGRD_DAT) >> kLynxPHY_REGRD_DATPhase;
  3179.         pLynxFWIMData->lastPhyReg0 = phyData;
  3180.         
  3181.         // PhysicalID reg is in the same spot for both old and extended PHY...
  3182.         newNodeID = (phyData & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
  3183.         
  3184.         if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3185.                 (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  3186.                 (UInt32 *) &busNodeID ))
  3187.             return;
  3188.             
  3189.         busNodeID = EndianSwap32Bit( busNodeID );
  3190.  
  3191.         busNodeID &= ~kLynxNODE_ID;
  3192.         busNodeID |= (newNodeID << kLynxNODE_IDPhase);
  3193.         
  3194.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  3195.                 (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  3196.                 (UInt32) EndianSwap32Bit (busNodeID) ))
  3197.             return;
  3198.         
  3199.         // If we got a reset interrupt during this interrupt (ie it was set when we entered the interrupt handler)
  3200.         // or if it is set now we make sure to keep the async receiver disabled so we don't ack packets for the wrong
  3201.         // node.  We check this by looking at the interrupt register now, or'ing it with what was there and checking the
  3202.         // reset bit. If there wasn't another reset then turn on the receiver.
  3203.         
  3204.         if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3205.                 (UInt32 *) &pLynxRegs->linkInterruptStatus,
  3206.                 (UInt32 *) &interruptLittleEndian ))
  3207.             return;
  3208.  
  3209.         interrupt |= EndianSwapImm32Bit (interruptLittleEndian);
  3210.  
  3211.         if( interrupt & kLynxPHY_BUSRESET ) {
  3212.         
  3213.             LynxFWIMClearLinkControlBits (pLynxFWIMData, EndianSwapImm32Bit( kLynxRX_ASYNC_EN ));
  3214.             
  3215.             // Since the reset interrupt we saw here may actually be the one which caused this phyregreceived
  3216.             // interrupt we set a timer to enable the receiver if we don't see any more resets in the next
  3217.             // few milliseconds.
  3218.             
  3219.             if( pLynxFWIMData->phyNodeThoughtValid ) {
  3220.             
  3221.                 // Cancel any previously pending timers.
  3222.                 status = CancelTimer (pLynxFWIMData->phyRegTimerID,
  3223.                                   &timeRemaining);
  3224.             }
  3225.  
  3226.             pLynxFWIMData->phyNodeThoughtValid = true;
  3227.             timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (3 * durationMillisecond));
  3228.             status = SetInterruptTimer
  3229.                         (&timeoutAbsolute,
  3230.                          LynxFWIMDelayedPhyRegReceived,
  3231.                          pLynxFWIMData,
  3232.                          &(pLynxFWIMData->phyRegTimerID));
  3233.         }
  3234.         else {
  3235.             LynxFWIMSetLinkControlBits (pLynxFWIMData, EndianSwapImm32Bit( kLynxRX_ASYNC_EN ));
  3236.         }
  3237.         
  3238.         // If there hasn't been another reset by now, this will let us receive packets.
  3239.         // If there was another reset, the async receiver is disabled, so this does nothing.
  3240.         
  3241.         LynxFWIMEnableComparators(pLynxFWIMData);
  3242.         
  3243.         // If there was a bus reset, and we were cycle master, and we aren't any more,
  3244.         // we need to turn off the cycle master ASAP in order to avoid PHY jams and to
  3245.         // avoid sending duplicate cycle starts.
  3246.  
  3247.         // Root reg is in the same spot for both old and extended PHY...
  3248.         if ((phyData & kLynxPhyR) == 0)        // if not root
  3249.         {
  3250.             if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3251.                     (UInt32 *) &pLynxRegs->linkControl,
  3252.                     (UInt32 *) &linkData ))
  3253.                 return;
  3254.             if (linkData & EndianSwapImm32Bit( kLynxCYCMASTER ))
  3255.             {
  3256.                 // zzz
  3257.                 // Although this should not conflict with someone setting CYCMASTER,
  3258.                 // It could conflict with other access to the LinkControl register.
  3259.                 // Those are rare, but they might re-enable cycle mastering, which is
  3260.                 // bad.  So this should be changed to a race-free method.
  3261.                 
  3262.                 // Disable cycle mastering.
  3263.                 LynxFWIMClearLinkControlBits
  3264.                     (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
  3265.             }
  3266.         }
  3267.     }
  3268. }
  3269.  
  3270.  
  3271. ////////////////////////////////////////////////////////////////////////////////
  3272. //
  3273. // LynxFWIMDelayedPhyRegReceived
  3274. //
  3275. // Enables the Async transmitter if we think we saw the last in a series of quick
  3276. // resets.
  3277. //
  3278. static OSStatus    LynxFWIMDelayedPhyRegReceived(
  3279.     void                        *p1,
  3280.     void                        *p2)
  3281. {
  3282.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  3283.     LynxRegistersPtr            pLynxRegs;
  3284.     UInt32                        interrupt;
  3285.     
  3286.     // Get base address of Lynx registers.
  3287.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3288.     
  3289.     (*(pLynxFWIMData->interruptDisabler)) (pLynxFWIMData->interruptSetMember,
  3290.                                                 (void *) pLynxFWIMData);    // >>•••••••>> Ints Off
  3291.                                                 
  3292.  
  3293.     if( pLynxFWIMData->phyNodeThoughtValid ) {
  3294.  
  3295.         // Disable comparator in case another reset comes in
  3296.         
  3297.         LynxFWIMDisableComparators(pLynxFWIMData);
  3298.     
  3299.         // Enable the receiver etc.
  3300.         LynxFWIMSetLinkControlBits (pLynxFWIMData, EndianSwapImm32Bit( kLynxRX_ASYNC_EN ));
  3301.         
  3302.         // If we got a reset interrupt while we had interrupts blocked we may have inadvertently re-enabled the
  3303.         // receiver. We don't want to enable the comparators if this is true. We check this by looking at the interrupt
  3304.         // register. If there wasn't another reset then turn on the comparators.
  3305.         
  3306.         if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3307.                 (UInt32 *) &pLynxRegs->linkInterruptStatus,
  3308.                 (UInt32 *) &interrupt ))
  3309.             return( accessErr );    // !!! Error message?
  3310.  
  3311.         interrupt = EndianSwap32Bit( interrupt );
  3312.  
  3313.         if( !( interrupt & kLynxPHY_BUSRESET) ) {
  3314.             LynxFWIMEnableComparators(pLynxFWIMData);
  3315.         }
  3316.  
  3317.     }
  3318.     
  3319.     (*(pLynxFWIMData->interruptEnabler)) (pLynxFWIMData->interruptSetMember,
  3320.                                                 (void *) pLynxFWIMData);    // <<•••••••<< Ints On
  3321.     
  3322.     pLynxFWIMData->phyNodeThoughtValid = false;
  3323.     
  3324.     return( noErr );
  3325.  
  3326. }
  3327.  
  3328. ////////////////////////////////////////////////////////////////////////////////
  3329. //
  3330. // LynxFWIMHandleMiscInterrupt
  3331. //
  3332. //   This proc handles miscellaneous interrupts.
  3333. //   This is only called #ifdef LynxFireBug
  3334. //  zzz no mechanism to prevent race condition in reporting.
  3335. //
  3336.  
  3337. static void LynxFWIMHandleMiscInterrupt(
  3338.     LynxFWIMDataPtr                pLynxFWIMData)
  3339. {
  3340.     UInt32                        intStatus;
  3341.     UInt32                        intEnable;
  3342.     OSStatus                    status = noErr;
  3343.  
  3344.     if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3345.             (UInt32 *) &pLynxFWIMData->pLynxRegisters->linkInterruptStatus,
  3346.             (UInt32 *) &intStatus ))
  3347.         return;
  3348.  
  3349.     if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  3350.             (UInt32 *) &pLynxFWIMData->pLynxRegisters->linkInterruptEnable,
  3351.             (UInt32 *) &intEnable ))
  3352.         return;
  3353.  
  3354.     pLynxFWIMData->miscInterrupt = EndianSwap32Bit ( intStatus & intEnable );
  3355.  
  3356.     // Schedule deferred task.
  3357.     if ((pLynxFWIMData->miscInterrupt) && !(pLynxFWIMData->miscInterruptDTScheduled))
  3358.     {
  3359.         status = FWScheduleDeferredTask (pLynxFWIMData->miscInterruptDeferredTaskID, nil);
  3360.  
  3361.         if (status == noErr)
  3362.             pLynxFWIMData->miscInterruptDTScheduled = true;
  3363.     }
  3364. }
  3365.  
  3366.  
  3367. ////////////////////////////////////////////////////////////////////////////////
  3368. //
  3369. // LynxFWIMResetBus
  3370. //
  3371. //   This routine initiates a bus reset.
  3372. //
  3373.  
  3374. static OSStatus LynxFWIMResetBus(
  3375.     FWIMCommandParamsPtr        pFWIMCommandParams,
  3376.     UInt32                        *pCommandAcceptance)
  3377. {
  3378.     LynxFWIMDataPtr                pLynxFWIMData;
  3379.     LynxRegistersPtr            pLynxRegs;
  3380.     UInt32                        phyReg;
  3381.     OSStatus                    status = noErr;
  3382.  
  3383.     // Get our internal data.
  3384.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3385.  
  3386.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3387.  
  3388. #ifdef LynxFireBug
  3389.     sprintf (fireBug, "LynxFWIM:  Bus reset from FSL");
  3390.     LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  3391. #endif
  3392.     
  3393.     // Set pending command.
  3394.     pLynxFWIMData->pPendingFWIMCommand = pFWIMCommandParams;
  3395.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3396.  
  3397.     // Get base address of Lynx registers.
  3398.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3399.  
  3400.     if( pLynxFWIMData->phyNotPowered )
  3401.         status = accessErr;     // !!! Proper error?
  3402.     
  3403.     // Stripped out a bunch of stuff related to PHY Jams on pre REV A parts.
  3404.     // The condition was apparently caused by doing a DV Transmit and a CCM
  3405.     // receive at the same time while moving the mouse.
  3406.     // Now we just issue the reset.
  3407.     
  3408.     // Issue the reset. IBR reg is in the same spot for both old and extended PHY...
  3409.     phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyIBRAddress);
  3410.     phyReg |= kLynxPhyIBR;
  3411.     LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyIBRAddress, phyReg);
  3412.  
  3413.     // Finish up command.
  3414.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3415.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3416.  
  3417.     // Return command acceptance.
  3418.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3419.     //zzz well, it still works, but will it always?
  3420.     //zzz actually, when we switch to the dispatch table, each routine can return
  3421.     //zzz the appropriate acceptance, so don't worry about it for now.
  3422.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3423.     
  3424.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3425.  
  3426.     return (status);
  3427. }
  3428.  
  3429.  
  3430. ////////////////////////////////////////////////////////////////////////////////
  3431. //
  3432. // LynxFWIMSetContenderBit
  3433. //
  3434. //   This routine sets the contender bit in the self ID on the next bus reset.
  3435. //
  3436.  
  3437. static OSStatus LynxFWIMSetContenderBit(
  3438.     FWIMCommandParamsPtr        pFWIMCommandParams,
  3439.     UInt32                        *pCommandAcceptance)
  3440. {
  3441.     LynxFWIMDataPtr                pLynxFWIMData;
  3442.     LynxRegistersPtr            pLynxRegs;
  3443.     UInt32                        lynxReg;
  3444.     OSStatus                    status = noErr;
  3445.     UInt32                        phyReg;
  3446.  
  3447.     // Get our internal data and register base address.
  3448.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3449.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3450.  
  3451.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3452.  
  3453.     // Set pending command.
  3454.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  3455.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3456.  
  3457.  
  3458.     if( pLynxFWIMData->phyNotPowered )
  3459.         status = paramErr;     // Fake FSL into loading us even if this doesn't work
  3460.     else {
  3461.         if( pLynxFWIMData->extendedPhyRegs ) {
  3462.             phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress);
  3463.             phyReg |= kLynxExtPhyCntd;
  3464.             LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress, phyReg);
  3465.         }
  3466.         else {
  3467.             // Program the contender bit to be set on next reset.
  3468.             //zzz ought to have routine for setting gpios.
  3469.             lynxReg = EndianSwap32Bit (pLynxRegs->gpioControlA);
  3470.             lynxReg = (lynxReg & ~(kLynxGPIO_SRC0 | kLynxGPIO_POL_OUT0)) | kLynxGPIO_OUT_EN0;
  3471.             pLynxRegs->gpioControlA = EndianSwap32Bit (lynxReg);
  3472.             SynchronizeIO ();
  3473.             pLynxRegs->gpioData[1] = EndianSwapImm32Bit (1);
  3474.             SynchronizeIO ();
  3475.         }
  3476.     }
  3477.  
  3478.     // Finish up command.
  3479.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3480.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3481.  
  3482.     // Return command acceptance.
  3483.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3484.     //zzz well, it still works, but will it always?
  3485.     //zzz actually, when we switch to the dispatch table, each routine can return
  3486.     //zzz the appropriate acceptance, so don't worry about it for now.
  3487.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3488.  
  3489.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3490.  
  3491.     return (status);
  3492. }
  3493.  
  3494.  
  3495. ////////////////////////////////////////////////////////////////////////////////
  3496. //
  3497. // LynxFWIMClearContenderBit
  3498. //
  3499. //   This routine clears the contender bit in the self ID on the next bus reset.
  3500. //
  3501.  
  3502. static OSStatus LynxFWIMClearContenderBit(
  3503.     FWIMCommandParamsPtr        pFWIMCommandParams,
  3504.     UInt32                        *pCommandAcceptance)
  3505. {
  3506.     LynxFWIMDataPtr                pLynxFWIMData;
  3507.     LynxRegistersPtr            pLynxRegs;
  3508.     UInt32                        lynxReg;
  3509.     OSStatus                    status = noErr;
  3510.     UInt32                        phyReg;
  3511.  
  3512.     // Get our internal data and register base address.
  3513.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3514.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3515.  
  3516.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3517.  
  3518.     // Set pending command.
  3519.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  3520.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3521.  
  3522.     if( pLynxFWIMData->phyNotPowered )
  3523.         status = accessErr;     // !!! Proper error?
  3524.     else {
  3525.         if( pLynxFWIMData->extendedPhyRegs ) {
  3526.             phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress);
  3527.             phyReg &= ~kLynxExtPhyCntd;
  3528.             LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxExtPhyCntdAddress, phyReg);
  3529.         }
  3530.         else {
  3531.             // Program the contender bit to be clear on next reset.
  3532.             //zzz ought to have routine for setting gpios.
  3533.             lynxReg = EndianSwap32Bit (pLynxRegs->gpioControlA);
  3534.             lynxReg = (lynxReg & ~(kLynxGPIO_SRC0 | kLynxGPIO_POL_OUT0)) | kLynxGPIO_OUT_EN0;
  3535.             pLynxRegs->gpioControlA = EndianSwap32Bit (lynxReg);
  3536.             SynchronizeIO ();
  3537.             pLynxRegs->gpioData[1] = EndianSwapImm32Bit (0);
  3538.             SynchronizeIO ();
  3539.         }
  3540.     }
  3541.  
  3542.     // Finish up command.
  3543.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3544.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3545.  
  3546.     // Return command acceptance.
  3547.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3548.     //zzz well, it still works, but will it always?
  3549.     //zzz actually, when we switch to the dispatch table, each routine can return
  3550.     //zzz the appropriate acceptance, so don't worry about it for now.
  3551.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3552.  
  3553.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3554.  
  3555.     return (status);
  3556. }
  3557.  
  3558.  
  3559. ////////////////////////////////////////////////////////////////////////////////
  3560. //
  3561. // LynxFWIMEnableCycleMaster
  3562. //
  3563. //   This routine enables cycle mastering.
  3564. //   Unlike the disable routine below, which is somewhat redundant, this routine
  3565. //   is the only place we set cycle master.  Setting cycle master is done only
  3566. //   after the IRM assigns a new cycle master, which is rare and isn't supposed
  3567. //   to be particularly fast. (ie, cycle loss is OK)
  3568. //
  3569. //   zzz should there be a mechanism to report failure, such as FSL asked us to
  3570. //   become cyclemaster, but by the time we got here, we aren't root anymore?
  3571. //
  3572.  
  3573. static OSStatus LynxFWIMEnableCycleMaster(
  3574.     FWIMCommandParamsPtr        pFWIMCommandParams,
  3575.     UInt32                        *pCommandAcceptance)
  3576. {
  3577.     LynxFWIMDataPtr                pLynxFWIMData;
  3578.     LynxRegistersPtr            pLynxRegs;
  3579.     OSStatus                    status = noErr;
  3580.     
  3581.     // Get our internal data and register base address.
  3582.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3583.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3584.  
  3585.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3586.  
  3587.     // Set pending command.
  3588.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  3589.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3590.  
  3591.     if( pLynxFWIMData->phyNotPowered )
  3592.         status = accessErr;     // !!! Proper error?
  3593.     
  3594.     // Enable cycle mastering if we're root.
  3595.     if ( !status && pLynxFWIMData->root)
  3596.     {
  3597.         // For safety, double-check that we're root: Root reg is in the same spot for both old and extended PHY...
  3598.         if (((volatile UInt8) (pLynxFWIMData->lastPhyReg0)) & kLynxPhyR)
  3599.         {
  3600.             LynxFWIMSetLinkControlBits
  3601.                 (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
  3602.  
  3603.             // And now, if we lost root, we may have screwed up linkControl.
  3604.             // This isn't perfect, but at least turn off the CYCMASTER
  3605.  
  3606.             if (!(((volatile UInt8) (pLynxFWIMData->lastPhyReg0)) & kLynxPhyR))
  3607.                 LynxFWIMClearLinkControlBits
  3608.                     (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
  3609.         }
  3610.     }
  3611.  
  3612.  
  3613.     // Finish up command.
  3614.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3615.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3616.  
  3617.     // Return command acceptance.
  3618.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3619.     //zzz well, it still works, but will it always?
  3620.     //zzz actually, when we switch to the dispatch table, each routine can return
  3621.     //zzz the appropriate acceptance, so don't worry about it for now.
  3622.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3623.  
  3624.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3625.  
  3626.     return (status);
  3627. }
  3628.  
  3629.  
  3630. ////////////////////////////////////////////////////////////////////////////////
  3631. //
  3632. // LynxFWIMDisableCycleMaster
  3633. //
  3634. //   This routine disables cycle mastering.
  3635. //   Note, this is somewhat redundant, because we will have turned off cycle
  3636. //   mastering at primary interrupt level as soon as we lose root status.  The
  3637. //   only case in which this function would really do anything is if FSL wanted
  3638. //   to stop being the cycle master even though we are the root node.
  3639. //
  3640.  
  3641. static OSStatus LynxFWIMDisableCycleMaster(
  3642.     FWIMCommandParamsPtr        pFWIMCommandParams,
  3643.     UInt32                        *pCommandAcceptance)
  3644. {
  3645.     LynxFWIMDataPtr                pLynxFWIMData;
  3646.     LynxRegistersPtr            pLynxRegs;
  3647.     OSStatus                    status = noErr;
  3648.  
  3649.     // Get our internal data and register base address.
  3650.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3651.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3652.  
  3653.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3654.  
  3655.     // Set pending command.
  3656.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  3657.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3658.  
  3659.     if( pLynxFWIMData->phyNotPowered )
  3660.         status = accessErr;     // !!! Proper error?
  3661.     
  3662.     // Disable cycle mastering.
  3663.     if( !status ) {
  3664.         LynxFWIMClearLinkControlBits
  3665.             (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
  3666.     }
  3667.  
  3668.     // Finish up command.
  3669.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3670.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3671.  
  3672.     // Return command acceptance.
  3673.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3674.     //zzz well, it still works, but will it always?
  3675.     //zzz actually, when we switch to the dispatch table, each routine can return
  3676.     //zzz the appropriate acceptance, so don't worry about it for now.
  3677.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3678.  
  3679.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3680.  
  3681.     return (status);
  3682. }
  3683.  
  3684.  
  3685. ////////////////////////////////////////////////////////////////////////////////
  3686. //
  3687. // LynxFWIMSetRootHoldoffBit
  3688. //
  3689. //   This routine sets the PHY root holdoff bit.
  3690. //
  3691.  
  3692. static OSStatus LynxFWIMSetRootHoldoffBit(
  3693.     FWIMCommandParamsPtr        pFWIMCommandParams,
  3694.     UInt32                        *pCommandAcceptance)
  3695. {
  3696.     LynxFWIMDataPtr                pLynxFWIMData;
  3697.     LynxRegistersPtr            pLynxRegs;
  3698.     UInt32                        phyReg;
  3699.     OSStatus                    status = noErr;
  3700.  
  3701.     // Get our internal data and register base address.
  3702.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3703.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3704.  
  3705.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3706.  
  3707.     // Set pending command.
  3708.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  3709.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3710.  
  3711.     if( pLynxFWIMData->phyNotPowered )
  3712.         status = accessErr;     // !!! Proper error?
  3713.     
  3714.     if( !status ) {
  3715.         // Set the root holdoff bit in the PHY. RHB reg is in the same spot for both old and extended PHY...
  3716.         phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyRHBAddress);
  3717.         phyReg |= kLynxPhyRHB;
  3718.         LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyRHBAddress, phyReg);
  3719.     }
  3720.  
  3721.     // Finish up command.
  3722.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3723.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3724.  
  3725.     // Return command acceptance.
  3726.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3727.     //zzz well, it still works, but will it always?
  3728.     //zzz actually, when we switch to the dispatch table, each routine can return
  3729.     //zzz the appropriate acceptance, so don't worry about it for now.
  3730.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3731.  
  3732.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3733.  
  3734.     return (status);
  3735. }
  3736.  
  3737.  
  3738. ////////////////////////////////////////////////////////////////////////////////
  3739. //
  3740. // LynxFWIMClearRootHoldoffBit
  3741. //
  3742. //   This routine clears the PHY root holdoff bit.
  3743. //
  3744.  
  3745. static OSStatus LynxFWIMClearRootHoldoffBit(
  3746.     FWIMCommandParamsPtr        pFWIMCommandParams,
  3747.     UInt32                        *pCommandAcceptance)
  3748. {
  3749.     LynxFWIMDataPtr                pLynxFWIMData;
  3750.     LynxRegistersPtr            pLynxRegs;
  3751.     UInt32                        phyReg;
  3752.     OSStatus                    status = noErr;
  3753.  
  3754.     // Get our internal data and register base address.
  3755.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3756.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3757.  
  3758.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3759.  
  3760.     // Set pending command.
  3761.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  3762.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3763.  
  3764.     if( pLynxFWIMData->phyNotPowered )
  3765.         status = accessErr;     // !!! Proper error?
  3766.     
  3767.     if( !status ) {
  3768.         // Clear the root holdoff bit in the PHY.  RHB reg is in the same spot for both old and extended PHY...
  3769.         phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyRHBAddress);
  3770.         phyReg &= ~kLynxPhyRHB;
  3771.         LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyRHBAddress, phyReg);
  3772.     }
  3773.  
  3774.     // Finish up command.
  3775.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3776.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3777.  
  3778.     // Return command acceptance.
  3779.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3780.     //zzz well, it still works, but will it always?
  3781.     //zzz actually, when we switch to the dispatch table, each routine can return
  3782.     //zzz the appropriate acceptance, so don't worry about it for now.
  3783.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3784.  
  3785.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3786.  
  3787.     return (status);
  3788. }
  3789.  
  3790.  
  3791. ////////////////////////////////////////////////////////////////////////////////
  3792. //
  3793. // LynxFWIMGetUniqueID
  3794. //
  3795. //   This routine returns the local unique ID.
  3796. //
  3797.  
  3798. static OSStatus    LynxFWIMGetUniqueID(
  3799.     FWIMGetUniqueIDParamsPtr    pFWIMGetUniqueIDParams,
  3800.     UInt32                        *pCommandAcceptance)
  3801. {
  3802.     LynxFWIMDataPtr                pLynxFWIMData;
  3803.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3804.     OSStatus                    status = noErr;
  3805.     
  3806.     // Get our internal data.
  3807.     pFWIMCommandParams = &(pFWIMGetUniqueIDParams->fwimCommandParams);
  3808.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3809.  
  3810.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3811.  
  3812.     if( !status ) {
  3813.         if (pLynxFWIMData->eepromValid)
  3814.         {
  3815.             pFWIMGetUniqueIDParams->uniqueID.hi = pLynxFWIMData->eepromInfo.busInfoBlock[2];
  3816.             pFWIMGetUniqueIDParams->uniqueID.lo = pLynxFWIMData->eepromInfo.busInfoBlock[3];
  3817.         }
  3818.         else
  3819.         {
  3820.             //zzz Fake it
  3821.             pFWIMGetUniqueIDParams->uniqueID.hi = 'lynx';
  3822.             pFWIMGetUniqueIDParams->uniqueID.lo = (UInt32) pLynxFWIMData;
  3823.         }
  3824.     }
  3825.     
  3826. //    sprintf (debugStr, "LynxFWIMGetUniqueID : Node Vendor ID %06lx   Chip ID %02lx%08lx",
  3827. //             (long) pFWIMGetUniqueIDParams->uniqueID.hi >> 8,
  3828. //             (long) pFWIMGetUniqueIDParams->uniqueID.hi & 0xff,
  3829. //             (long) pFWIMGetUniqueIDParams->uniqueID.lo);
  3830. //    FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  3831.     
  3832.     // Finish up command.
  3833.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3834.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3835.  
  3836.     // Return command acceptance.
  3837.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3838.     //zzz well, it still works, but will it always?
  3839.     //zzz actually, when we switch to the dispatch table, each routine can return
  3840.     //zzz the appropriate acceptance, so don't worry about it for now.
  3841.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3842.  
  3843.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3844.  
  3845.     return (status);
  3846. }
  3847.  
  3848.  
  3849. ////////////////////////////////////////////////////////////////////////////////
  3850. //
  3851. // LynxFWIMSendLinkOnPacket
  3852. //
  3853. //   This proc sends the given link on packet.
  3854. //
  3855.  
  3856. static OSStatus    LynxFWIMSendLinkOnPacket(
  3857.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  3858.     UInt32                        *pCommandAcceptance)
  3859. {
  3860.     LynxFWIMDataPtr                pLynxFWIMData;
  3861.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3862.     UInt32                        linkOnData;
  3863.     OSStatus                    status = noErr;
  3864.     
  3865.     // Get our internal data.
  3866.     pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
  3867.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3868.  
  3869.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3870.  
  3871.     // Set pending command.
  3872.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
  3873.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3874.  
  3875.     if( pLynxFWIMData->phyNotPowered )
  3876.         status = accessErr;     // !!! Proper error?
  3877.  
  3878.     if( !status ) {
  3879.         // Check if generation is up to date.
  3880.         if ((!(pLynxFWIMData->generationValid)) ||
  3881.             (pFWIMSendPhyPacketParams->generation != pLynxFWIMData->generation))
  3882.         {
  3883.             status = busReconfiguredErr;
  3884.         }
  3885.     }
  3886.  
  3887.     // Set up link on data.
  3888.     if (status == noErr)
  3889.     {
  3890.         linkOnData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
  3891.         linkOnData &= ~kFWPhyPacketID;
  3892.         linkOnData |= kFWLinkOnPacketID << kFWPhyPacketIDPhase;
  3893.     }
  3894.     
  3895.     // Send packet.
  3896.     if (status == noErr)
  3897.     {
  3898.         LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_UNFORMATTED_XMT, kFWSpeed100MBit, 2,
  3899.                           linkOnData, ~linkOnData, 0, 0, 0, 0);
  3900.     }
  3901.  
  3902.     // Finish up command.
  3903.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3904.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3905.  
  3906.     // Return command acceptance.
  3907.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3908.     //zzz well, it still works, but will it always?
  3909.     //zzz actually, when we switch to the dispatch table, each routine can return
  3910.     //zzz the appropriate acceptance, so don't worry about it for now.
  3911.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3912.  
  3913.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3914.  
  3915.     return (status);
  3916. }
  3917.  
  3918.  
  3919. ////////////////////////////////////////////////////////////////////////////////
  3920. //
  3921. // LynxFWIMSendPhyConfigurationPacket
  3922. //
  3923. //   This proc sends the given Phy configuration packet.
  3924. //
  3925.  
  3926. static OSStatus    LynxFWIMSendPhyConfigurationPacket(
  3927.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  3928.     UInt32                        *pCommandAcceptance)
  3929. {
  3930.     LynxFWIMDataPtr                pLynxFWIMData;
  3931.     FWIMCommandParamsPtr        pFWIMCommandParams;
  3932.     UInt32                        configurationData;
  3933.     OSStatus                    status = noErr;
  3934.     
  3935.     // Get our internal data.
  3936.     pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
  3937.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  3938.  
  3939.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  3940.  
  3941.     // Set pending command.
  3942.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
  3943.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  3944.  
  3945.     if( pLynxFWIMData->phyNotPowered )
  3946.         status = accessErr;     // !!! Proper error?
  3947.  
  3948.     if( !status ) {
  3949.         // Check if generation is up to date.
  3950.         if ((!(pLynxFWIMData->generationValid)) ||
  3951.             (pFWIMSendPhyPacketParams->generation != pLynxFWIMData->generation))
  3952.         {
  3953.             status = busReconfiguredErr;
  3954.         }
  3955.     }
  3956.  
  3957.     // Set up phy configuration data.
  3958.     if (status == noErr)
  3959.     {
  3960.         configurationData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
  3961.         configurationData &= ~kFWPhyPacketID;
  3962.         configurationData |= kFWConfigurationPacketID << kFWPhyPacketIDPhase;
  3963.     }
  3964.     
  3965.     // Send packet.
  3966.     if (status == noErr)
  3967.     {
  3968.         LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_UNFORMATTED_XMT, kFWSpeed100MBit, 2,
  3969.                           configurationData, ~configurationData, 0, 0, 0, 0);
  3970.     }
  3971.  
  3972.     // Finish up command.
  3973.     pLynxFWIMData->pPendingFWIMCommand = nil;
  3974.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  3975.  
  3976.     // Return command acceptance.
  3977.     //zzz what if we call FWIMCommandIsComplete before returning this???
  3978.     //zzz well, it still works, but will it always?
  3979.     //zzz actually, when we switch to the dispatch table, each routine can return
  3980.     //zzz the appropriate acceptance, so don't worry about it for now.
  3981.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3982.  
  3983.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  3984.  
  3985.     return (status);
  3986. }
  3987.  
  3988.  
  3989. ////////////////////////////////////////////////////////////////////////////////
  3990. //
  3991. // LynxFWIMSetCSRROM
  3992. //
  3993. //   In an OpenHCI FWIM, this routine would activate a new CSR ROM image
  3994. //     using the hardware map.  Lynx can't do that, so we just cause a bus
  3995. //     reset instead.  This is provided largely as a sample to show what to
  3996. //   to for OpenHCI.  We do go through all the "motions" of OHCI.
  3997. //
  3998.  
  3999. static OSStatus LynxFWIMSetCSRROM(
  4000.     FWIMSetCSRROMParamsPtr        pFWIMSetCSRROMParams,
  4001.     UInt32                        *pCommandAcceptance)
  4002. {
  4003.     LynxFWIMDataPtr                pLynxFWIMData;
  4004.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4005.     UInt32                        phyReg;
  4006.     OSStatus                    status = noErr;
  4007.  
  4008.     // Get our internal data.
  4009.     pFWIMCommandParams = &(pFWIMSetCSRROMParams->fwimCommandParams);
  4010.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4011.  
  4012.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  4013.  
  4014.     // Set pending command.
  4015.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  4016.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  4017.  
  4018.      // Can't return an error from this guy or FWIM won't load. If the bus comes alive again
  4019.     // we'll issue a reset anyway.
  4020.     if( !pLynxFWIMData->phyNotPowered ) {
  4021.         
  4022.         // If this was an OpenHCI FWIM, we would copy the ROM image into a private
  4023.         // buffer that we have already mapped (not the active one, a second buffer).
  4024.         // The new ROM is at pFWIMSetCSRROMParams->pCSRROM and it has a length
  4025.         // of pFWIMSetCSRROMParams->length, which we ignore for now and is always 1024.
  4026.         // In theory we then do a CheckPointIO (kMoreIO).  Then we set an internal flag
  4027.         // indicating special treatment for the next bus reset.  The flag is equal to
  4028.         // the pointer FSL gave us:
  4029.         
  4030.         pLynxFWIMData->csrROMUpdateClearWhenDone = pFWIMSetCSRROMParams->clearWhenDone;
  4031.         
  4032.         // Next, both Lynx and OpenHCI cause a bus reset:
  4033.         
  4034.         if (status == noErr) {
  4035.             // Issue a reset. IBR reg is in the same spot for both old and extended PHY...
  4036.             phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyIBRAddress);
  4037.             phyReg |= kLynxPhyIBR;
  4038.             LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyIBRAddress, phyReg);
  4039.         }
  4040.     
  4041.         // Now, OpenHCI will do some more work.  But not here, it's in the Bus Reset
  4042.         // Interrupt handler (LynxFWIMHandleResetInterrupt):  As soon as the bus reset
  4043.         // actually comes in, store a new value in the Config ROM Mapping Register
  4044.         // (section 5.5.6), and also immediately copy new values into the Config ROM
  4045.         // Header Register (5.5.2) and the Bus Options Register (5.5.4).  Then tell FSL
  4046.         // that the requested work is done.  Once this is done, immediately cause
  4047.         // *another* bus reset.
  4048.     }
  4049.     
  4050.     // Finish up command.
  4051.     pLynxFWIMData->pPendingFWIMCommand = nil;
  4052.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  4053.  
  4054.     // Return command acceptance.
  4055.     //zzz what if we call FWIMCommandIsComplete before returning this???
  4056.     //zzz well, it still works, but will it always?
  4057.     //zzz actually, when we switch to the dispatch table, each routine can return
  4058.     //zzz the appropriate acceptance, so don't worry about it for now.
  4059.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  4060.  
  4061.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  4062.  
  4063.     return status;
  4064. }
  4065.  
  4066.  
  4067. ////////////////////////////////////////////////////////////////////////////////
  4068. //
  4069. // LynxFWIMDoLocalCompareSwap
  4070. //
  4071. //   This routine does a Compare/Swap on a hardware-supported bus management
  4072. //   register.  This is never called for LynxFWIM because we don't report that
  4073. //   feature.  This is just sample code for OpenHCI.  But, note that any FWIM
  4074. //   that reports version 1.1 or above must have a dispatch table entry for this.
  4075. //
  4076.  
  4077. static OSStatus    LynxFWIMDoLocalCompareSwap(
  4078.     FWIMCompareSwapParamsPtr    pFWIMCompareSwapParams)
  4079. {
  4080.     LynxFWIMDataPtr                pLynxFWIMData;
  4081.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4082.     OSStatus                    status = noErr;
  4083.     
  4084.     // Get our internal data.
  4085.     pFWIMCommandParams = &(pFWIMCompareSwapParams->fwimCommandParams);
  4086.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4087.  
  4088.     if( pLynxFWIMData->phyNotPowered )
  4089.         status = accessErr;     // !!! Proper error?
  4090.     
  4091.     if (status == noErr) {
  4092.         //OpenHCI would immediatly use the Bus Management CSR Registers (5.5.1)
  4093.         //to perform the requested action:
  4094.         
  4095.         //The OHCI spec doesn't say this clearly, but a compare/swap should be
  4096.         //very fast, and is not supposed to fail.
  4097.         
  4098.         //The steps go something like this (don't forget endian swaps...):
  4099.         //  Load csrData with pFWIMCompareSwapParams->oldValue
  4100.         //  Load csrCompare with pFWIMCompareSwapParams->newValue
  4101.         //  Load csrSel with pFWIMCompareSwapParams->targetRegister
  4102.         //  Poll for csrDone (slowly - don't hammer the chip if it's in the middle of DMA.
  4103.         //                    for example, do 5 SynchronizeIO()'s between polls.)
  4104.         //  Load pFWIMCompareSwapParams->returnValue with csrData
  4105.         
  4106.         // It might be wise to time out on csrDone after 0.01ms or so and set returnValue to ~oldValue,
  4107.         // (inverse of oldValue) which indicates failure, just in case somehow the chip ignores the request.
  4108.     }
  4109.         
  4110.     return status;
  4111. }
  4112.  
  4113.  
  4114. ////////////////////////////////////////////////////////////////////////////////
  4115. //
  4116. // LynxFWIMSetAsynchFilters
  4117. //
  4118. //   In an OpenHCI FWIM, this routine attempts to set both the asynch request
  4119. //   filters (5.13.1) and the physical request filters (5.13.2).  Other FWIMs
  4120. //   that have physical capability could also honor these requests.  This
  4121. //   dispatch entry is required, regardless of the support level, in any FWIM
  4122. //   that reports version 1.1 or higher.
  4123. //
  4124. //   In OpenHCI, the filters can be changed by a bus reset.  This call should
  4125. //   simply attempt to set the filters as requested, then return the actual
  4126. //   values.  Multiple attempts should not be made (FSL will fix things up
  4127. //   after a bus reset).
  4128.  
  4129. static OSStatus LynxFWIMSetAsynchFilters(
  4130.     FWIMSetAsynchFiltersParamsPtr    pFWIMSetAsynchFiltersParams)
  4131. {
  4132.     LynxFWIMDataPtr                pLynxFWIMData;
  4133.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4134.     OSStatus                    status = noErr;
  4135.  
  4136.     // Get our internal data.
  4137.     pFWIMCommandParams = &(pFWIMSetAsynchFiltersParams->fwimCommandParams);
  4138.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4139.  
  4140.     // If the PHY is not powered, we'll get a bus reset before any further asynch
  4141.     // traffic.  So the settings don't matter, and we can just return.
  4142.     
  4143.     if( pLynxFWIMData->phyNotPowered )
  4144.         status = accessErr;     // !!! Proper error?
  4145.         
  4146.     if (status == noErr) {
  4147.         // OpenHCI would do it kind of like this:
  4148.         //pOHCI->AsynchSetHi = pFWIMSetAsynchFiltersParams->asynchFilterHi;
  4149.         //pOHCI->AsynchClearHi = ~pFWIMSetAsynchFiltersParams->asynchFilterHi;
  4150.         //... repeat for Lo and Physical
  4151.  
  4152.         //Now return filter values:
  4153.         //pFWIMSetAsynchFiltersParams->asynchFilterHi = pOHCI->AsynchSetHi;
  4154.         //... etc.
  4155.         
  4156.     }
  4157.     
  4158.     return status;
  4159. }
  4160.  
  4161.  
  4162. ////////////////////////////////////////////////////////////////////////////////
  4163. //
  4164. // LynxFWIMSetFWIMState
  4165. //
  4166. //   Puts the FWIM to sleep or wakes it back up again.
  4167. //   For Idle and Sleep we need to insure we will not ever call the FSL until
  4168. //   we are make active or standby again. This is so the FSL can be fovr'd 
  4169. //     from "ROM" and not get called while in the process of getting replaced.
  4170. //     Eventually we will use this call to save power by turning FWIMs
  4171. //     off.
  4172. //
  4173.  
  4174. static OSStatus LynxFWIMSetFWIMState(
  4175.     FWIMSetFWIMStateParamsPtr    pFWIMSetFWIMStateParams)
  4176. {
  4177.  
  4178.     LynxFWIMDataPtr                pLynxFWIMData;
  4179.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4180.     OSStatus                    status = noErr;
  4181.  
  4182.     // Get our internal data.
  4183.     pFWIMCommandParams = &(pFWIMSetFWIMStateParams->fwimCommandParams);
  4184.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4185.  
  4186.     // What do we do here if we are being asked to go to sleep? Nothing? !!!
  4187.     //if( pLynxFWIMData->phyNotPowered )
  4188.     //    status = accessErr;     // !!! Proper error?
  4189.     
  4190.     switch( pFWIMSetFWIMStateParams->fwimState ) {
  4191.     
  4192.     case kFWIMActive:
  4193.     case kFWIMStandby:
  4194.         // Try to make the FWIM active if we need to.
  4195.         
  4196.         if( pLynxFWIMData->phyNotPowered ) {
  4197.         
  4198.             LynxFWIMAttemptPHYWakeup( (void *)pLynxFWIMData, nil );
  4199.             
  4200.             // If we couldn't wakeup then the PHY is not powered.
  4201.             if( pLynxFWIMData->phyNotPowered )
  4202.                 status = accessErr;
  4203.         }
  4204.             
  4205.         break;
  4206.         
  4207.     case kFWIMIdle:
  4208.     case kFWIMSleep:    
  4209.         // With one of these guys we need to quiesce the FWIM. Since
  4210.         // for a LynxFWIM this is the same thing as operating without PHY
  4211.         // power we'll just pretend we have an umpowered PHY until told otherwise.
  4212.         
  4213.         LynxFWIMWaitForPHYPower(pLynxFWIMData,true);
  4214.         break;
  4215.  
  4216.     default:
  4217.         status = paramErr;
  4218.         break;
  4219.     
  4220.     }
  4221.  
  4222.  
  4223.     return( status );
  4224. }
  4225.  
  4226.  
  4227. ////////////////////////////////////////////////////////////////////////////////
  4228. //
  4229. // LynxFWIMGetCycleTime
  4230. //
  4231. //   This routine returns the current value of the cycle timer register.
  4232. //
  4233.  
  4234. static OSStatus    LynxFWIMGetCycleTime(
  4235.     FWIMGetCycleTimeParamsPtr    pFWIMGetCycleTimeParams)
  4236. {
  4237.     LynxFWIMDataPtr                pLynxFWIMData;
  4238.     OSStatus                    status = noErr;
  4239.     
  4240.     // Get our internal data.
  4241.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMGetCycleTimeParams->fwimCommandParams.fwimSpecificData;
  4242.  
  4243.     if (pLynxFWIMData->phyNotPowered)
  4244.         status = accessErr;     // !!! Proper error?
  4245.     
  4246.     if (status == noErr)
  4247.         *(pFWIMGetCycleTimeParams->pCycleTime) =
  4248.             EndianSwap32Bit (pLynxFWIMData->pLynxRegisters->cycleTimer);
  4249.     
  4250.     return status;
  4251. }
  4252.  
  4253.  
  4254. ////////////////////////////////////////////////////////////////////////////////
  4255. //
  4256. // LynxFWIMWritePhyRegister
  4257. //
  4258. //   This proc writes data to the specified phy register.
  4259. //
  4260.  
  4261. static void    LynxFWIMWritePhyRegister(
  4262.     LynxFWIMDataPtr                pLynxFWIMData,
  4263.     UInt8                        regAddress,
  4264.     UInt8                        regData)
  4265. {
  4266.     LynxRegistersPtr            pLynxRegs;
  4267.     UInt32                        phyChipAccess;
  4268.     UInt32                        patience;
  4269.     UInt32                        phyData;
  4270.  
  4271. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister");
  4272.  
  4273.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4274.  
  4275.     if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  4276.             (UInt32 *) &pLynxRegs->phyControl,
  4277.             (UInt32 *) &phyData ) )
  4278.         return;
  4279.  
  4280.     if (phyData & EndianSwapImm32Bit (kLynxWRPHY))
  4281.         FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister - write bit already set!!!");
  4282.  
  4283.     // Set up phyChipAccess to write phy.
  4284.     // Set the write bit, the register address, and data.
  4285.     phyChipAccess = kLynxWRPHY;
  4286.     phyChipAccess |= (regAddress << kLynxPHY_REG_ADRPhase) & kLynxPHY_REG_ADR;
  4287.     phyChipAccess |= (regData << kLynxPHY_REG_DATPhase) & kLynxPHY_REG_DAT;
  4288.  
  4289.     if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  4290.             (UInt32 *) &pLynxRegs->phyControl,
  4291.             (UInt32) EndianSwap32Bit (phyChipAccess) ))
  4292.         return;
  4293.         
  4294.     patience = 100000;
  4295.     while (patience-- ) 
  4296.     {
  4297.         if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  4298.                 (UInt32 *) &pLynxRegs->phyControl,
  4299.                 (UInt32 *) &phyData ))
  4300.             return;
  4301.             
  4302.         if( !(phyData & EndianSwapImm32Bit (kLynxWRPHY)) )
  4303.             break;    // Done
  4304.             
  4305.         if (!patience)
  4306.             FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister:  waited too long");
  4307.     }
  4308. }
  4309.  
  4310.  
  4311. ////////////////////////////////////////////////////////////////////////////////
  4312. //
  4313. // LynxFWIMReadPhyRegister
  4314. //
  4315. //   This proc reads data from the specified phy register.
  4316. //   This has the side effect of triggering a PHY received interrupt,
  4317. //   which should be harmless.
  4318. // zzz Still need to make the timeouts use real time, not CPU clocks.
  4319. //
  4320.  
  4321. static UInt8    LynxFWIMReadPhyRegister(
  4322.     LynxFWIMDataPtr                pLynxFWIMData,
  4323.     UInt8                        regAddress)
  4324. {
  4325.     LynxRegistersPtr            pLynxRegs;
  4326.     UInt32                        phyChipAccess,
  4327.                                 phyChipAccessRead;
  4328.     UInt8                        returnedAddress;
  4329.     UInt8                        regData;
  4330.     UInt32                        patience;
  4331.     UInt32                        phyData;
  4332.  
  4333. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister");
  4334.  
  4335.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4336.  
  4337.     // Set up phyChipAccess register to read phy.
  4338.     // Set read bit, register address, and set returned read address to an
  4339.     // invalid phy address, so we can tell when it changes.
  4340.     phyChipAccessRead = kLynxRDPHY;
  4341.     phyChipAccessRead |= (regAddress << kLynxPHY_REG_ADRPhase) & kLynxPHY_REG_ADR;
  4342.     phyChipAccessRead |= (kLynxPhyInvalidAddress << kLynxPHY_REGRD_ADRPhase) &
  4343.                          kLynxPHY_REGRD_ADR;
  4344.                          
  4345.     if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  4346.             (UInt32 *) &pLynxRegs->phyControl,
  4347.             (UInt32) EndianSwap32Bit (phyChipAccessRead) ))
  4348.         return( 0 );
  4349.                      
  4350.     // Wait for the desired return read address.
  4351.     // Tests show that this typically takes 10 microseconds,
  4352.     // though I have seen it take up to 330 microseconds.
  4353.     // Of course, if the card has wedged, this will take forever.
  4354.     do
  4355.     {
  4356.         // Wait for read to be sent.
  4357.         patience = 2000;
  4358.         while (patience-- )
  4359.         {
  4360.             UInt32 wait = 2000;
  4361.  
  4362.             if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  4363.                     (UInt32 *) &pLynxRegs->phyControl,
  4364.                     (UInt32 *) &phyData ))
  4365.                 return( 0 );
  4366.                 
  4367.             if( !(phyData & EndianSwapImm32Bit (kLynxRDPHY)) )
  4368.                 break;    // Done
  4369.                 
  4370.             while (wait--) SynchronizeIO();
  4371.             if (!patience)
  4372.             {
  4373.                 if (NoPhyReset)
  4374.                 {
  4375.                     FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister - WAITED TOO LONG, but cannot reset right now");
  4376.                     return 0;
  4377.                 }
  4378.                 else
  4379.                 {
  4380.                     FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister - WAITED TOO LONG, full card reset");
  4381.                     LynxFWIMFullReset();
  4382.                 }
  4383.             }
  4384.         }
  4385.  
  4386.         if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  4387.                 (UInt32 *) &pLynxRegs->phyControl,
  4388.                 (UInt32 *) &phyChipAccess ))
  4389.             return( 0 ); 
  4390.         phyChipAccess = EndianSwap32Bit (phyChipAccess);
  4391.  
  4392.         // Read returned address.
  4393.         returnedAddress = (phyChipAccess & kLynxPHY_REGRD_ADR) >>
  4394.                           kLynxPHY_REGRD_ADRPhase;
  4395.  
  4396.         // If RDPHY still set, make sure we don't accept the value
  4397.         if (phyChipAccess & kLynxRDPHY)
  4398.             returnedAddress = 0xfff;
  4399.             
  4400.         // If returned address is not what we we're looking for and not what
  4401.         // we set it to, start another read.
  4402.         if ((returnedAddress != regAddress) &&
  4403.             (returnedAddress != kLynxPhyInvalidAddress))
  4404.         {
  4405.             if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  4406.                     (UInt32 *) &pLynxRegs->phyControl,
  4407.                     (UInt32) EndianSwap32Bit (phyChipAccessRead) ))
  4408.                 return(0);
  4409.         }
  4410.     } while (returnedAddress != regAddress);
  4411.  
  4412.     // Extract and return phy register contents.
  4413.     regData = (phyChipAccess & kLynxPHY_REGRD_DAT) >>
  4414.               kLynxPHY_REGRD_DATPhase;
  4415.     return regData;
  4416. }
  4417.  
  4418.  
  4419. ////////////////////////////////////////////////////////////////////////////////
  4420. //
  4421. // LynxFWIMPrepareAsyncDMA
  4422. //
  4423. //   This proc perpares PCLs for async receive and primes the DMA.
  4424. //
  4425.  
  4426. static void LynxFWIMPrepareAsyncDMA(
  4427.     LynxFWIMDataPtr                pLynxFWIMData,
  4428.     UInt32                        channel)
  4429. {
  4430.     // Create the async receive PCL program.
  4431.     LynxFWIMCreateAsyncRxPCLProgram (pLynxFWIMData);
  4432.  
  4433.     // Start async receive PCL program.
  4434.     LynxFWIMStartAsyncRxPCLProgram
  4435.         (pLynxFWIMData, &(pLynxFWIMData->asyncPCL[kAsyncRxFirstPacketPCL]));
  4436. }
  4437.  
  4438.  
  4439. ////////////////////////////////////////////////////////////////////////////////
  4440. //
  4441. // LynxFWIMAddAsyncRxPCL
  4442. //
  4443. //   This proc adds a PCL to the active async receive PCL list.
  4444. //
  4445.  
  4446. static void LynxFWIMAddAsyncRxPCL(
  4447.     LynxPCLPtr                    pPCL)
  4448. {
  4449.     LynxFWIMDataPtr                pLynxFWIMData;
  4450.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData,
  4451.                                 pPrevLynxAsyncRxPCLData,
  4452.                                 pOverflowLynxAsyncRxPCLData;
  4453.     LynxPCLPtr                    pPrevPCL,
  4454.                                 pOverflowPCL;
  4455.  
  4456.     // Get PCL data and Lynx FWIM data for PCL to add.
  4457.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  4458.     pLynxFWIMData = pLynxAsyncRxPCLData->pLynxFWIMData;
  4459.  
  4460.     // Get PCL and PCL data for overflow handling.
  4461.     pOverflowPCL = pLynxFWIMData->asyncRxOverflowPCLSegment;
  4462.     pOverflowLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pOverflowPCL->refCon;
  4463.  
  4464.     // Link new PCL to overflow handler and invalidate new PCL's status.
  4465.     pPCL->nextPCL =
  4466.         (UInt32 *) EndianSwap32Bit ((UInt32) pOverflowLynxAsyncRxPCLData->pPCLPhysical);
  4467.     pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
  4468.     pLynxAsyncRxPCLData->pNextPCL = nil;
  4469.  
  4470.     // Get last async receive PCL.
  4471.     pPrevPCL = pLynxFWIMData->pLastAsyncPCL;
  4472.  
  4473.     // Link new PCL to last one.
  4474.     if ((pPrevPCL != nil) && (pLynxFWIMData->pNextAsyncPCL != nil))
  4475.     {
  4476.         pPrevPCL->nextPCL =
  4477.             (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncRxPCLData->pPCLPhysical);
  4478.         pPrevLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPrevPCL->refCon;
  4479.         pPrevLynxAsyncRxPCLData->pNextPCL = pPCL;
  4480.     }
  4481.     else
  4482.     {
  4483.         pLynxFWIMData->pNextAsyncPCL = pPCL;
  4484.     }
  4485.  
  4486.     // Check for overflow.
  4487.     if (pLynxFWIMData->asyncRxOverflowFlag)
  4488.     {
  4489.         // Restart async receive PCL program at new PCL if it's still unused.
  4490.         if (pPCL->status == EndianSwapImm32Bit (kLynxInvalidStatus))
  4491.             LynxFWIMStartAsyncRxPCLProgram (pLynxFWIMData, pPCL);
  4492.     }
  4493.  
  4494.     // New PCL is now last.
  4495.     pLynxFWIMData->pLastAsyncPCL = pPCL;
  4496. }
  4497.  
  4498.  
  4499. ////////////////////////////////////////////////////////////////////////////////
  4500. //
  4501. // LynxFWIMCreateAsyncRxPCLProgram
  4502. //
  4503. //   This proc creates the async receive PCL program.
  4504. //
  4505.  
  4506. static void LynxFWIMCreateAsyncRxPCLProgram(
  4507.     LynxFWIMDataPtr                pLynxFWIMData)
  4508. {
  4509.     LynxFWIMDataPtr                pPhysLynxFWIMData;
  4510.     LynxRegistersPtr            pLynxRegs;
  4511.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  4512.     LynxPCLPtr                    pPCL;
  4513.     UInt32                        pclNum,
  4514.                                 packetNum;
  4515.     
  4516.     // Get pointer to link registers and physical pointer to FWIM data.
  4517.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4518.     pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
  4519.  
  4520.     // Create dummy PCL for starting.
  4521.     LynxFWIMCreateAsyncRxDummyPCL (pLynxFWIMData);
  4522.  
  4523.     // Create overflow segment.
  4524.     LynxFWIMCreateAsyncRxOverflowPCLSegment (pLynxFWIMData);
  4525.  
  4526.     // Create packet PCLs.
  4527.     for (pclNum = kAsyncRxFirstPacketPCL, packetNum = 0;
  4528.          pclNum <= kAsyncRxLastPacketPCL;
  4529.          pclNum++, packetNum++)
  4530.     {
  4531.         // Get pointer to PCL.
  4532.         pPCL = &(pLynxFWIMData->asyncPCL[pclNum]);
  4533.  
  4534.         // Add PCL data record.
  4535.         pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[pclNum]);
  4536.         pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
  4537.         pLynxAsyncRxPCLData->pPCLPhysical =
  4538.             pLynxFWIMData->asyncPCLPhys + (pclNum * sizeof (LynxPCL));
  4539.         pLynxAsyncRxPCLData->packetBuffer = pLynxFWIMData->asyncBuf[packetNum];
  4540.         pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
  4541.  
  4542.         // Initialize PCL header.
  4543.         pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  4544.  
  4545.         // Set up PCL buffers.
  4546.         pPCL->buffer[0].control =
  4547.             EndianSwapImm32Bit ((kLynxDMA_RCV << kLynxDMA_CMDPhase) |
  4548.                                 kLynxDMA_LAST_BUF |
  4549.                                 kPacketBufferSize |
  4550.                                 kLynxDMA_INT);
  4551.         pPCL->buffer[0].address =
  4552.             (UInt32 *) EndianSwap32Bit ((UInt32) pLynxFWIMData->asyncBufPhys[packetNum]);
  4553.  
  4554.         // Add PCL to program.
  4555.         LynxFWIMAddAsyncRxPCL (pPCL);
  4556.     }
  4557. }
  4558.  
  4559.  
  4560. ////////////////////////////////////////////////////////////////////////////////
  4561. //
  4562. // LynxFWIMCreateAsyncRxDummyPCL
  4563. //
  4564. //   This proc creates a dummy PCL for starting the async receive PCL program.
  4565. //
  4566.  
  4567. static void LynxFWIMCreateAsyncRxDummyPCL(
  4568.     LynxFWIMDataPtr                pLynxFWIMData)
  4569. {
  4570.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  4571.     LynxPCLPtr                    pPCL;
  4572.  
  4573.     // Just fill in the basics.
  4574.     pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxDummyPCL]);
  4575.     pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[kAsyncRxDummyPCL]);
  4576.     pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
  4577.     pLynxAsyncRxPCLData->pPCLPhysical =
  4578.         pLynxFWIMData->asyncPCLPhys + (kAsyncRxDummyPCL * sizeof (LynxPCL));
  4579.     pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
  4580. }
  4581.  
  4582.  
  4583. ////////////////////////////////////////////////////////////////////////////////
  4584. //
  4585. // LynxFWIMCreateAsyncRxOverflowPCLSegment
  4586. //
  4587. //   This proc creates the async receive overflow PCL segment.
  4588. //zzz what should happen if we get to end of list?
  4589. //
  4590.  
  4591. static void LynxFWIMCreateAsyncRxOverflowPCLSegment(
  4592.     LynxFWIMDataPtr                pLynxFWIMData)
  4593. {
  4594.     LynxFWIMDataPtr                pPhysLynxFWIMData;
  4595.     LynxRegistersPtr            pLynxRegs;
  4596.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  4597.     LynxPCLPtr                    pPCL;
  4598.  
  4599.     // This PCL goes at the end of the async receive PCL program.  If we run out
  4600.     // of async receive PCLs, we want to do a controlled shutdown so that we send
  4601.     // the right ack code on any future packets (ack_busyX).  So this PCL sets a
  4602.     // bit that causes ack_busyX for all packets.  That way, packets don't pile up
  4603.     // in the GRF.
  4604.     
  4605.     // At present, some packets could be in the FIFO by the time we set the busyX
  4606.     // bit.  Those packets will linger there until we recover, and they will
  4607.     // block any incoming isoch packets.  That's not good.  We should add more PCLs
  4608.     // after this one that will drain the FIFO (but not bitbucket the packets).
  4609.  
  4610.     // By leaving the comparator enabled, we send busyX, which hopefully will buy
  4611.     // us some time.  Here's a rundown of how Lynx determines ack values:
  4612.     
  4613.     // After a bus reset, the async receiver is disabled.  We don't ack any packet.
  4614.     // If the Async receiver is enabled, then each packet is checked against the
  4615.     // nodeID set in register 0xF00.  Packets for other nodes are ignored.
  4616.     //
  4617.     // If the incoming packet matches our node ID, then...
  4618.     //   If there is no comparator enabled that matches the packet, send no ack.
  4619.     //      [A Lynx at the other end will see a Link Timeout]
  4620.     //   If there is a comparator enabled that matches the packet...
  4621.     //      If the busy bit in register 0xF04 is set, send ack_busyX
  4622.     //      If not, try to receive the packet...
  4623.     //        If there is a FIFO overflow, send ack_busyX
  4624.     //        If there is a CRC error, send ack_dataErr (probably.  Very rare)
  4625.     //        If we're still OK...
  4626.     //          If it's a broadcast packet, send no ack.
  4627.     //          If it's a write and the comparator has WRITE_REQ_ACK_SEL, send ack_complete
  4628.     //          Otherwise send ack_pending
  4629.  
  4630.     // Note that we do set WRITE_REQ_ACK_SEL so that we won't have to send a write
  4631.     // response later.  This is why any packets left over in the FIFO after we run
  4632.     // out of PCLs must still be received - if we sent ack_complete, and they are
  4633.     // write requests, we must not throw them away.  We already said we took care of them.
  4634.     
  4635.     // Get pointer to link registers and physical pointer to FWIM data.
  4636.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4637.     pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
  4638.  
  4639.     // Set up PCL to busy incoming packets.
  4640.     //zzz should be a little cleaner
  4641.     pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxOverrunPCL]);
  4642.     pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  4643.     pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  4644.     pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[kAsyncRxOverrunPCL]);
  4645.     pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
  4646.     pLynxAsyncRxPCLData->pPCLPhysical =
  4647.             pLynxFWIMData->asyncPCLPhys + (kAsyncRxOverrunPCL * sizeof (LynxPCL));
  4648.     pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
  4649.     pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
  4650.     pPCL->remaining = EndianSwapImm32Bit (0);
  4651.     pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
  4652.  
  4653.     // If we leave the comparator enabled, but set this busy bit, then we'll
  4654.     // send ack_busyX to all inbound async packets.  If we turn the comparator
  4655.     // off too (like we used to) then we won't ack packets at all, which may
  4656.     // confuse the sender.
  4657.     
  4658.     // Set link to busy all async packets.
  4659.     pPCL->buffer[0].control = EndianSwapImm32Bit (kLynxDMA_LOAD << kLynxDMA_CMDPhase);
  4660.     pPCL->buffer[0].address = (UInt32 *)
  4661.         EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncRxOverflowSetLinkControl));
  4662.     pPCL->buffer[1].control =
  4663.         EndianSwapImm32Bit (kLynxDMA_STORE_QUAD << kLynxDMA_CMDPhase);
  4664.     pPCL->buffer[1].address =
  4665.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxRegs->linkControl));    // !!! if accessing the link control register fails, how do we tell?
  4666.  
  4667.     // Historical note - we used to turn off the comparator.  That prevents the
  4668.     // bit for sending ack_busyX from working and causes us to send no ack.  So
  4669.     // we don't do that anymore.
  4670.     
  4671.     // Set overflow flag so software knows this happened
  4672.     pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
  4673.     pPCL->buffer[2].control =
  4674.         EndianSwapImm32Bit ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  4675.     pPCL->buffer[2].address =
  4676.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncRxOverflowFlag));
  4677.  
  4678.     // Set PCL segment in FWIM data.
  4679.     pLynxFWIMData->asyncRxOverflowPCLSegment = pPCL;
  4680. }
  4681.  
  4682.  
  4683. ////////////////////////////////////////////////////////////////////////////////
  4684. //
  4685. // LynxFWIMStartAsyncRxPCLProgram
  4686. //
  4687. //   This proc starts the async receive PCL program.
  4688. //
  4689.  
  4690. static void LynxFWIMStartAsyncRxPCLProgram(
  4691.     LynxFWIMDataPtr                pLynxFWIMData,
  4692.     LynxPCLPtr                    pStartPCL)
  4693. {
  4694.     LynxRegistersPtr            pLynxRegs;
  4695.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData,
  4696.                                 pStartLynxAsyncRxPCLData;
  4697.     LynxPCLPtr                    pPCL;
  4698.     Boolean                        asyncRxReady = false;
  4699.  
  4700.     // Get pointer to link registers and start PCL's data.
  4701.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4702.  
  4703.     // Check for overflow.
  4704.     if (pLynxFWIMData->asyncRxOverflowFlag)
  4705.     {
  4706.         // Check if we've started priming.
  4707.         if (pLynxFWIMData->numAsyncRxPCLsPrimed == 0)
  4708.         {
  4709.             pLynxFWIMData->pStartAsyncRxPCL = pStartPCL;
  4710.             pLynxFWIMData->numAsyncRxPCLsPrimed = 1;
  4711.         }
  4712.         else
  4713.         {
  4714.             pLynxFWIMData->numAsyncRxPCLsPrimed++;
  4715.         }
  4716.  
  4717.         // Check if we've primed enough receive PCLs.
  4718.         if (pLynxFWIMData->numAsyncRxPCLsPrimed >= kLynxNumAsyncRxPCLsToPrime)
  4719.         {
  4720.             pLynxFWIMData->asyncRxOverflowFlag = 0;
  4721.             pLynxFWIMData->numAsyncRxPCLsPrimed = 0;
  4722.             asyncRxReady = true;
  4723.         }
  4724.     }
  4725.     else
  4726.     {
  4727.         // We're ready to receive.
  4728.         pLynxFWIMData->pStartAsyncRxPCL = pStartPCL;
  4729.         asyncRxReady = true;
  4730.     }
  4731.  
  4732.     if (asyncRxReady)
  4733.     {
  4734.         // Quiet the DMA channel.
  4735.         pLynxRegs->dmaChannel[pLynxFWIMData->asyncRxDMA].control = EndianSwapImm32Bit (0);
  4736.         SynchronizeIO();
  4737.     
  4738.         // Start the PCL program at the given PCL.
  4739.         pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxDummyPCL]);
  4740.         pStartLynxAsyncRxPCLData =
  4741.             (LynxAsyncRxPCLDataPtr) pLynxFWIMData->pStartAsyncRxPCL->refCon;
  4742.         pPCL->nextPCL =
  4743.             (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncRxPCLData->pPCLPhysical);
  4744.         pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  4745.         pLynxRegs->dmaChannel[pLynxFWIMData->asyncRxDMA].curPCLAddr =
  4746.             EndianSwap32Bit ((UInt32) pLynxAsyncRxPCLData->pPCLPhysical);
  4747.         SynchronizeIO();
  4748.     
  4749.         // Note, not clear that the ready register really matters here
  4750.         
  4751.         // Enable the DMA.
  4752.         pLynxRegs->dmaChannel[pLynxFWIMData->asyncRxDMA].ready = EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
  4753.         SynchronizeIO();
  4754.         pLynxRegs->dmaChannel[pLynxFWIMData->asyncRxDMA].control =
  4755.             EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  4756.         SynchronizeIO();
  4757.     
  4758.         // Really only need to do this once
  4759.         
  4760.         // Enable comparator.
  4761.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  4762.                     (UInt32 *) &pLynxRegs->dmaComparator[pLynxFWIMData->asyncRxDMA].mask0,
  4763.                     (UInt32) EndianSwapImm32Bit (kLynxAsynctCodeNormal << kLynxCMP0_FIELD3_MASKPhase)))
  4764.             return;
  4765.  
  4766.         LynxFWIMSetAsyncRxComparatorMask1
  4767.             (pLynxFWIMData,
  4768.              kLynxRCV_SELF_ID_EN |
  4769.              kLynkDEST_ID_SEL_BusNode |
  4770.              kLynxEN_CH_COMPARE |
  4771.              kLynxWRITE_REQ_ACK_SEL);
  4772.     
  4773.         // Clear busy flag in linkControl.
  4774.         LynxFWIMClearLinkControlBits
  4775.             (pLynxFWIMData, EndianSwapImm32Bit( kLynxBUSY_CNTRL ));
  4776.     }
  4777. }
  4778.  
  4779.  
  4780. ////////////////////////////////////////////////////////////////////////////////
  4781. //
  4782. // LynxFWIMAddAsyncTxPCL
  4783. //
  4784. //   This proc adds a PCL to the active async transmit PCL list.
  4785. //
  4786.  
  4787. static void LynxFWIMAddAsyncTxPCL(
  4788.     LynxPCLPtr                    pPCL)
  4789. {
  4790.     LynxFWIMDataPtr                pLynxFWIMData;
  4791.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData,
  4792.                                 pPrevLynxAsyncTxPCLData,
  4793.                                 pDoneLynxAsyncRxPCLData;
  4794.     LynxPCLPtr                    pPrevPCL,
  4795.                                 pDonePCL;
  4796.  
  4797.     // Get PCL data and Lynx FWIM data for PCL to add.
  4798.     pLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPCL->refCon;
  4799.     pLynxFWIMData = pLynxAsyncTxPCLData->pLynxFWIMData;
  4800.  
  4801.     // Get PCL and PCL data for done handling.
  4802.     pDonePCL = pLynxFWIMData->asyncTxDonePCLSegment;
  4803.     pDoneLynxAsyncRxPCLData = (LynxAsyncTxPCLDataPtr) pDonePCL->refCon;
  4804.  
  4805.     // Link new PCL to done handler and invalidate new PCL's status.
  4806.     pPCL->nextPCL =
  4807.         (UInt32 *) EndianSwap32Bit ((UInt32) pDoneLynxAsyncRxPCLData->pPCLPhysical);
  4808.     pPCL->nextPCLAlt =
  4809.         (UInt32 *) EndianSwap32Bit ((UInt32) pDoneLynxAsyncRxPCLData->pPCLPhysical);
  4810.     pLynxAsyncTxPCLData->pNextPCL = nil;
  4811.     pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
  4812.  
  4813.     // Get last async transmit PCL.
  4814.     pPrevPCL = pLynxFWIMData->pLastAsyncTxPCL;
  4815.  
  4816.     // Link new PCL to last one.
  4817.     if ((pPrevPCL != nil) && (pLynxFWIMData->pNextAsyncTxPCL != nil))
  4818.     {
  4819.         pPrevPCL->nextPCL =
  4820.             (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);
  4821.         pPrevPCL->nextPCLAlt =
  4822.             (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);//zzz is this the best?
  4823.         pPrevLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPrevPCL->refCon;
  4824.         pPrevLynxAsyncTxPCLData->pNextPCL = pPCL;
  4825.     }
  4826.     else
  4827.     {
  4828.         pLynxFWIMData->pNextAsyncTxPCL = pPCL;
  4829.     }
  4830.  
  4831.     // Check for asynchronous transmit done.
  4832.     if (pLynxFWIMData->asyncTxDoneFlag)
  4833.     {
  4834.         // Restart async transmit PCL program at new PCL if it's still unused.
  4835.         if (pPCL->status == EndianSwapImm32Bit (kLynxInvalidStatus))
  4836.             LynxFWIMStartAsyncTxPCLProgram (pLynxFWIMData, pPCL);
  4837.     }
  4838.  
  4839.     // New PCL is now last.
  4840.     pLynxFWIMData->pLastAsyncTxPCL = pPCL;
  4841. }
  4842.  
  4843.  
  4844. ////////////////////////////////////////////////////////////////////////////////
  4845. //
  4846. // LynxFWIMCreateAsyncTxDummyPCL
  4847. //
  4848. //   This proc creates a dummy PCL for starting the async transmit PCL program.
  4849. //
  4850.  
  4851. static void LynxFWIMCreateAsyncTxDummyPCL(
  4852.     LynxFWIMDataPtr                pLynxFWIMData)
  4853. {
  4854.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData;
  4855.     LynxPCLPtr                    pPCL;
  4856.  
  4857.     // Just fill in the basics.
  4858.     pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDummyPCL]);
  4859.     pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDummyPCL]);
  4860.     pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
  4861.     pLynxAsyncTxPCLData->pPCLPhysical =
  4862.         pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDummyPCL * sizeof (LynxPCL));
  4863.     pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
  4864. }
  4865.  
  4866.  
  4867. ////////////////////////////////////////////////////////////////////////////////
  4868. //
  4869. // LynxFWIMCreateAsyncTxDonePCLSegment
  4870. //
  4871. //   This proc creates the async transmit done PCL segment.
  4872. //
  4873.  
  4874. static void LynxFWIMCreateAsyncTxDonePCLSegment(
  4875.     LynxFWIMDataPtr                pLynxFWIMData)
  4876. {
  4877.     LynxFWIMDataPtr                pPhysLynxFWIMData;
  4878.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData;
  4879.     LynxPCLPtr                    pPCL;
  4880.  
  4881.     // Get physical pointer to FWIM data.
  4882.     pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
  4883.  
  4884.     // Set up PCL to set done flag.
  4885.     pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDonePCL]);
  4886.     pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  4887.     pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  4888.     pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDonePCL]);
  4889.     pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
  4890.     pLynxAsyncTxPCLData->pPCLPhysical =
  4891.         pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDonePCL * sizeof (LynxPCL));
  4892.     pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
  4893.     pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
  4894.     pPCL->remaining = EndianSwapImm32Bit (0);
  4895.     pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
  4896.  
  4897.     // Set done flag.
  4898.     pLynxFWIMData->asyncTxDoneFlag = 0xFFFFFFFF;
  4899.     pPCL->buffer[0].control =
  4900.         EndianSwapImm32Bit ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  4901.     pPCL->buffer[0].address =
  4902.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncTxDoneFlag));
  4903.  
  4904.     // Set PCL segment in FWIM data.
  4905.     pLynxFWIMData->asyncTxDonePCLSegment = pPCL;
  4906. }
  4907.  
  4908.  
  4909. ////////////////////////////////////////////////////////////////////////////////
  4910. //
  4911. // LynxFWIMCreateAsyncTxDataPCL
  4912. //
  4913. //   This proc creates a data PCL for the async transmit PCL program.
  4914. //
  4915.  
  4916. static void LynxFWIMCreateAsyncTxDataPCL(
  4917.     LynxFWIMDataPtr                pLynxFWIMData)
  4918. {
  4919.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData;
  4920.     LynxPCLPtr                    pPCL;
  4921.  
  4922.     // Just fill in the basics.
  4923.     pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]);
  4924.     pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDataPCL]);
  4925.     pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
  4926.     pLynxAsyncTxPCLData->pPCLPhysical =
  4927.         pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDataPCL * sizeof (LynxPCL));
  4928.     pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
  4929. }
  4930.  
  4931.  
  4932. ////////////////////////////////////////////////////////////////////////////////
  4933. //
  4934. // LynxFWIMStartAsyncTxPCLProgram
  4935. //
  4936. //   This proc starts the async transmit PCL program.
  4937. //
  4938.  
  4939. static void LynxFWIMStartAsyncTxPCLProgram(
  4940.     LynxFWIMDataPtr                pLynxFWIMData,
  4941.     LynxPCLPtr                    pStartPCL)
  4942. {
  4943.     LynxRegistersPtr            pLynxRegs;
  4944.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData,
  4945.                                 pStartLynxAsyncTxPCLData;
  4946.     LynxPCLPtr                    pPCL;
  4947.     Boolean                        asyncTxReady = false;
  4948.  
  4949.     // Clear done flag.
  4950.     pLynxFWIMData->asyncTxDoneFlag = 0;
  4951.  
  4952.     // Get pointer to link registers and start PCL's data.
  4953.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4954.  
  4955.     // Quiet the DMA channel.
  4956.     pLynxRegs->dmaChannel[pLynxFWIMData->asyncTxDMA].control = EndianSwapImm32Bit (0);
  4957.     SynchronizeIO();
  4958.  
  4959.     // Start the PCL program at the given PCL.
  4960.     pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDummyPCL]);
  4961.     pStartLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pStartPCL->refCon;
  4962.     pPCL->nextPCL =
  4963.         (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncTxPCLData->pPCLPhysical);
  4964.     pPCL->nextPCLAlt =
  4965.         (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncTxPCLData->pPCLPhysical);
  4966.     pLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPCL->refCon;
  4967.     pLynxRegs->dmaChannel[pLynxFWIMData->asyncTxDMA].curPCLAddr =
  4968.         EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);
  4969.     SynchronizeIO();
  4970.  
  4971.     // Enable the DMA.
  4972.     pLynxRegs->dmaChannel[pLynxFWIMData->asyncTxDMA].ready =
  4973.         EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
  4974.     SynchronizeIO();
  4975.     pLynxRegs->dmaChannel[pLynxFWIMData->asyncTxDMA].control =
  4976.         EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  4977.     SynchronizeIO();
  4978. }
  4979.  
  4980.  
  4981. ////////////////////////////////////////////////////////////////////////////////
  4982. //
  4983. // LynxFWIMSafeRegisterRead
  4984. //
  4985. //   This proc uses DMA to access a PCI register. This is useful because if
  4986. //   the PHY is not powered correctly accesses to Lynx registers at 0xB00 and
  4987. //   above will bus error. Since we don't know how to safely recover from this
  4988. //   we use DMA for these register accesses. If the DMA bus-errors it just
  4989. //   halts which is no problem for us or the user.
  4990. //
  4991. //   This makes for some messy code. In particular this function needs to be
  4992. //   re-entrant. Also it shares a DMA channel with the asynchronous transmit
  4993. //   section. We need to be careful to let whatever that channel was doing
  4994. //   finish before we try to use the channel. Finishing means the DMA either
  4995. //   stops or the transmitter gets turned off by a reset.
  4996. //
  4997.  
  4998. static OSStatus LynxFWIMSafeRegisterRead(
  4999.     LynxFWIMDataPtr                pLynxFWIMData,
  5000.     UInt32                        * registerAddress,
  5001.     UInt32                        * registerData )
  5002. {
  5003.     LynxRegistersPtr            pLynxRegs;
  5004.     SInt32                        stackPtr;
  5005.     LynxPCLPtr                    pPCL;
  5006.     UInt32                        waitFlag;
  5007.     OSStatus                    status = noErr;
  5008.     
  5009.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5010.     
  5011.     // We don't want to get stepped on if this code gets re-entered. To avoid this each
  5012.     // instance gets its own set of PCLs, allocated on a stack. The stack is actually just 
  5013.     // an index into an array of PCLs.
  5014.     
  5015.     stackPtr = IncrementAtomic( &pLynxFWIMData->phyRegAccessStack);
  5016.     stackPtr <<= 1;    // Two PCLs per instance
  5017.     
  5018.     // Wait for DMA to stop (flag will never get set)
  5019.     waitFlag = 0;
  5020.     status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kDMARegisterAccess, &waitFlag, 0xFFFFFFFF );
  5021.  
  5022.     if( status )
  5023.         goto end;    // Turn on read responses? Probably need a reset now anyway
  5024.  
  5025.     // Setup the PCLs and Buffers as follows:
  5026.     
  5027.     // PCL[0] Points to PCL[1] 
  5028.     
  5029.     // PCL[1] Points to Invalid PCL (1)
  5030.     // Buffer[0] Loads Quad from registerAddress
  5031.     // Buffer[1] Stores Quad to Buffer[3].control
  5032.     // Buffer[2] Store1 to Address Field of Buffer[3]. This Buffer is marked as the last one.
  5033.     // Buffer[3] Address Field is the completion flag, Control field is the data.
  5034.  
  5035.     // Create the DummyPCL
  5036.     pPCL = &(pLynxFWIMData->phyRegAccessLog[kRegAccessDummyPCL + stackPtr]);
  5037.     pPCL->nextPCL =
  5038.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr]));
  5039.     pPCL->nextPCLAlt =
  5040.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr]));
  5041.  
  5042.  
  5043.     // Setup the real PCL that does the work
  5044.     pPCL = &(pLynxFWIMData->phyRegAccessLog[kRegAccessPCL + stackPtr]);
  5045.  
  5046.     pPCL->nextPCL =
  5047.         (UInt32 *) EndianSwap32Bit ((UInt32) 1);
  5048.     pPCL->nextPCLAlt =
  5049.         (UInt32 *) EndianSwap32Bit ((UInt32) 1);
  5050.  
  5051.     // Buffer[0] Loads Quad from registerAddress
  5052.     pPCL->buffer[0].control = EndianSwapImm32Bit ((UInt32) (kLynxDMA_LOAD << kLynxDMA_CMDPhase));
  5053.     pPCL->buffer[0].address = (UInt32 *)
  5054.         EndianSwap32Bit ((UInt32) registerAddress );
  5055.  
  5056.     // Buffer[1] Stores Quad to Buffer[3].control
  5057.     pPCL->buffer[1].control = EndianSwapImm32Bit ((UInt32) (kLynxDMA_STORE_QUAD << kLynxDMA_CMDPhase));
  5058.     pPCL->buffer[1].address = (UInt32 *)
  5059.         EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr].buffer[3].control));
  5060.  
  5061.     // Buffer[2] Store1 to Address Field of Buffer[3]. This Buffer is marked as the last one.
  5062.     pPCL->buffer[2].control = EndianSwapImm32Bit ((UInt32) ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF));
  5063.     pPCL->buffer[2].address = (UInt32 *)
  5064.         EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr].buffer[3].address) );
  5065.  
  5066.     pPCL->buffer[3].address = 0;
  5067.     pPCL->buffer[3].control = 0;    // For consistency if we return an error
  5068.     
  5069.     // Keep trying to run the program til it succeeds or we notice a reset or timeout condition.
  5070.     while( !pPCL->buffer[3].address ) {
  5071.     
  5072.         // Start the Rx PCL program at the given PCL.
  5073.         pLynxRegs->dmaChannel[kDMARegisterAccess].curPCLAddr =
  5074.             EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessDummyPCL + stackPtr]));
  5075.         SynchronizeIO();
  5076.     
  5077.         // Enable the DMA.
  5078.         pLynxRegs->dmaChannel[kDMARegisterAccess].ready =
  5079.             EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
  5080.         SynchronizeIO();
  5081.         pLynxRegs->dmaChannel[kDMARegisterAccess].control =
  5082.             EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  5083.         SynchronizeIO();
  5084.  
  5085.         // Wait for DMA to stop
  5086.         status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kDMARegisterAccess, (UInt32 *)&pPCL->buffer[3].address, 0xFFFFFFFF );
  5087.         if( status )
  5088.             goto end;    // Turn on read responses? Probably need a reset now anyway
  5089.     }
  5090.     
  5091. end:
  5092.     // Suspend FWIM, wait 5 seconds for power to come back
  5093.     if( status )
  5094.         LynxFWIMWaitForPHYPower(pLynxFWIMData,false);
  5095.     else
  5096.         *registerData = pPCL->buffer[3].control;
  5097.     DecrementAtomic( &pLynxFWIMData->phyRegAccessStack);
  5098.     return(status);
  5099. }    
  5100.     
  5101. ////////////////////////////////////////////////////////////////////////////////
  5102. //
  5103. // LynxFWIMSafeRegisterWrite
  5104. //
  5105. //   This proc uses DMA to access a PCI register. This is useful because if
  5106. //   the PHY is not powered correctly accesses to Lynx registers at 0xB00 and
  5107. //   above will bus error. Since we don't know how to safely recover from this
  5108. //   we use DMA for these register accesses. If the DMA bus-errors it just
  5109. //   halts which is no problem for us or the user.
  5110. //
  5111. //   This makes for some messy code. In particular this function needs to be
  5112. //   re-entrant. Also it shares a DMA channel with the asynchronous transmit
  5113. //   section. We need to be careful to let whatever that channel was doing
  5114. //   finish before we try to use the channel. Finishing means the DMA either
  5115. //   stops or the transmitter gets turned off by a reset.
  5116. //
  5117.  
  5118. static OSStatus LynxFWIMSafeRegisterWrite( 
  5119.     LynxFWIMDataPtr                pLynxFWIMData,
  5120.     UInt32                        * registerAddress,
  5121.     UInt32                        registerData )
  5122. {
  5123.     LynxRegistersPtr            pLynxRegs;
  5124.     SInt32                        stackPtr;
  5125.     LynxPCLPtr                    pPCL;
  5126.     UInt32                        waitFlag;
  5127.     OSStatus                    status = noErr;
  5128.     
  5129.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5130.  
  5131.     // We don't want to get stepped on if this code gets re-entered. To avoid this each
  5132.     // instance gets its own set of PCLs, allocated on a stack. The stack is actually just 
  5133.     // an index into an array of PCLs.
  5134.     
  5135.     stackPtr = IncrementAtomic( &pLynxFWIMData->phyRegAccessStack);
  5136.     stackPtr <<= 1;    // Two PCLs per instance
  5137.     
  5138.     // Wait for DMA to stop (flag will never get set)
  5139.     waitFlag = 0;
  5140.     status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kDMARegisterAccess, &waitFlag, 0xFFFFFFFF );
  5141.     if( status )
  5142.         goto end;    // Turn on read responses? Probably need a reset now anyway
  5143.     
  5144.     // Setup the PCLs and Buffers as follows:
  5145.     
  5146.     // PCL[0] Points to PCL[1] 
  5147.     
  5148.     // PCL[1] Points to Invalid PCL (1)
  5149.     // Buffer[0] Loads Quad from registerData as stored in buffer[3].control
  5150.     // Buffer[1] Stores Quad to registerAddress
  5151.     // Buffer[2] Store1 to Address Field of Buffer[3]. This Buffer is marked as the last one.
  5152.     // Buffer[3] Address Field is the completion flag
  5153.  
  5154.     // Create the DummyPCL
  5155.     pPCL = &(pLynxFWIMData->phyRegAccessLog[kRegAccessDummyPCL + stackPtr]);
  5156.     pPCL->nextPCL =
  5157.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr]));
  5158.     pPCL->nextPCLAlt =
  5159.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr]));
  5160.  
  5161.  
  5162.     // Setup the real PCL that does the work
  5163.     pPCL = &(pLynxFWIMData->phyRegAccessLog[kRegAccessPCL + stackPtr]);
  5164.  
  5165.     pPCL->nextPCL =
  5166.         (UInt32 *) EndianSwap32Bit ((UInt32) 1);
  5167.     pPCL->nextPCLAlt =
  5168.         (UInt32 *) EndianSwap32Bit ((UInt32) 1);
  5169.  
  5170.     // Buffer[0] Loads Quad from registerData as stored in buffer[3].control
  5171.     pPCL->buffer[0].control = EndianSwapImm32Bit ((UInt32) (kLynxDMA_LOAD << kLynxDMA_CMDPhase));
  5172.     pPCL->buffer[0].address = (UInt32 *)
  5173.         EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr].buffer[3].control) );
  5174.  
  5175.     // Buffer[1] Stores Quad to registerAddress
  5176.     pPCL->buffer[1].control = EndianSwapImm32Bit ((UInt32) (kLynxDMA_STORE_QUAD << kLynxDMA_CMDPhase));
  5177.     pPCL->buffer[1].address = (UInt32 *)
  5178.         EndianSwap32Bit ((UInt32) registerAddress );
  5179.  
  5180.     // Buffer[2] Store1 to Address Field of Buffer[3]. This Buffer is marked as the last one.
  5181.     pPCL->buffer[2].control = EndianSwapImm32Bit ((UInt32) ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF));
  5182.     pPCL->buffer[2].address = (UInt32 *)
  5183.         EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessPCL + stackPtr].buffer[3].address) );
  5184.  
  5185.     pPCL->buffer[3].address = 0;
  5186.     pPCL->buffer[3].control = registerData;
  5187.     
  5188.     // Keep trying to run the program til it succeeds or we notice a reset or timeout condition.
  5189.     while( !pPCL->buffer[3].address ) {
  5190.     
  5191.         // Start the Rx PCL program at the given PCL.
  5192.         pLynxRegs->dmaChannel[kDMARegisterAccess].curPCLAddr =
  5193.             EndianSwap32Bit ((UInt32) &(pLynxFWIMData->phyRegAccessPhys[kRegAccessDummyPCL + stackPtr]));
  5194.         SynchronizeIO();
  5195.     
  5196.         // Enable the DMA.
  5197.         pLynxRegs->dmaChannel[kDMARegisterAccess].ready =
  5198.             EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
  5199.         SynchronizeIO();
  5200.         pLynxRegs->dmaChannel[kDMARegisterAccess].control =
  5201.             EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  5202.         SynchronizeIO();
  5203.  
  5204.         // Wait for DMA to stop (flag will never get set)
  5205.         status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kDMARegisterAccess, (UInt32 *)&pPCL->buffer[3].address, 0xFFFFFFFF );
  5206.         if( status )
  5207.             goto end;    // Turn on read responses? Probably need a reset now anyway
  5208.     }
  5209.     
  5210. end:
  5211.     // Suspend FWIM, wait 5 seconds for power to come back
  5212.     if( status )
  5213.         LynxFWIMWaitForPHYPower(pLynxFWIMData,false);
  5214.         
  5215.     DecrementAtomic( &pLynxFWIMData->phyRegAccessStack);
  5216.     return(status);
  5217. }    
  5218.  
  5219. ////////////////////////////////////////////////////////////////////////////////
  5220. //
  5221. // LynxFWIMSetRegisterBits
  5222. //
  5223. //   Uses the above DMA routines to set some bits in a register field. The
  5224. //   register is read, and the new bits are or'd in and then the register
  5225. //   is written back.
  5226. //
  5227.  
  5228. static OSStatus LynxFWIMSetRegisterBits( 
  5229.     LynxFWIMDataPtr                pLynxFWIMData,
  5230.     UInt32                        * registerAddress,
  5231.     UInt32                        registerData )
  5232. {
  5233.     UInt32                        existingRegisterData;
  5234.     OSStatus                    status = noErr;
  5235.     
  5236.     status = LynxFWIMSafeRegisterRead( pLynxFWIMData, registerAddress, &existingRegisterData);
  5237.  
  5238.     if( !status ) {
  5239.         existingRegisterData |= registerData;
  5240.         status = LynxFWIMSafeRegisterWrite( pLynxFWIMData, registerAddress, existingRegisterData );
  5241.     }
  5242.  
  5243.     return( status );
  5244. }
  5245.  
  5246. ////////////////////////////////////////////////////////////////////////////////
  5247. //
  5248. // LynxFWIMClearRegisterBits
  5249. //
  5250. //   Uses the above DMA routines to clear some bits in a register field. The
  5251. //   register is read, and the new bits are and'd with the complement of what
  5252. //   was already there and the result is is written back.
  5253. //
  5254.  
  5255. static OSStatus LynxFWIMClearRegisterBits( 
  5256.     LynxFWIMDataPtr                pLynxFWIMData,
  5257.     UInt32                        * registerAddress,
  5258.     UInt32                        registerData )
  5259. {
  5260.     UInt32                        existingRegisterData;
  5261.     OSStatus                    status = noErr;
  5262.     
  5263.     status = LynxFWIMSafeRegisterRead( pLynxFWIMData, registerAddress, &existingRegisterData);
  5264.  
  5265.     if( !status ) {
  5266.         existingRegisterData &= ~registerData;
  5267.         status = LynxFWIMSafeRegisterWrite( pLynxFWIMData, registerAddress, existingRegisterData );
  5268.     }
  5269.  
  5270.     return( status );
  5271. }
  5272.  
  5273. ////////////////////////////////////////////////////////////////////////////////
  5274. //
  5275. // LynxFWIMWaitAsyncTXFree
  5276. //
  5277. //   Waits for the TX channel to finish what its doing.
  5278. //
  5279.  
  5280. static OSStatus LynxFWIMWaitAsyncTXFree( 
  5281.     LynxFWIMDataPtr                pLynxFWIMData,
  5282.     UInt32                        dmaChannel,
  5283.     UInt32                        * waitFlag,
  5284.     UInt32                        waitValue )    
  5285. {
  5286.     LynxRegistersPtr            pLynxRegs;
  5287.     AbsoluteTime                timeoutAbsolute, timeLeft;
  5288.     UInt32                        patience;
  5289.     OSStatus                    status = noErr;
  5290.  
  5291.     // Get pointer to link registers.
  5292.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5293.  
  5294.     // Wait for the following to tell us the transmit/register access DMA on this channel has
  5295.     // completed:
  5296.     //
  5297.     // If the DMA is stopped we are done.
  5298.     // If the transmitter is off we are done
  5299.     // If we have waited 50 ms and nothing has happend we are done.
  5300.     // If *waitFlag == waitValue we are done
  5301.     //
  5302.  
  5303.     // Start with a short delay in case its done already.
  5304.     // We need at least a short delay here cause the Link part will choke if
  5305.     // we access it quickly enough after it issues a target abort - or at least
  5306.     // as far as I can tell. -DCB
  5307.     timeoutAbsolute =
  5308.         AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (25 * durationMicrosecond));
  5309.  
  5310.     // Wait at most 50 milliseconds.
  5311.     patience = 50;
  5312.  
  5313.     while( patience && (*waitFlag != waitValue) )
  5314.     {
  5315.         // Check only rarely for bus reset or DMA stopping
  5316.         timeLeft = SubAbsoluteFromAbsolute (timeoutAbsolute, UpTime ());  // returns 0 if negative
  5317.         if (AbsoluteToDuration (timeLeft) == 0)        
  5318.         {
  5319.             // We used to check for the transmitter becoming disabled here. We no longer do this because accessing
  5320.             // that register requires a DMA safe read which, well, brings us back here. Now we just wait for the
  5321.             // 50 millisecond timeout instead. Seems reasonable, as the bus would have been reset anyway at that 
  5322.             // point.
  5323.             if( !patience || !(EndianSwap32Bit(pLynxRegs->dmaChannel[dmaChannel].control) & kLynxDMA_BSY) )
  5324.             {
  5325.                 pLynxRegs->dmaChannel[dmaChannel].control = EndianSwapImm32Bit (0);
  5326.                 SynchronizeIO ();
  5327.         
  5328.                 *waitFlag = waitValue; // Tell whomevers waiting this puppy is a done as its gonna get
  5329.                 
  5330.                 if( !(EndianSwap32Bit(pLynxRegs->dmaChannel[dmaChannel].control) & kLynxDMA_BSY) ) {
  5331.                     if( pLynxRegs->dmaChannel[dmaChannel].status & EndianSwapImm32Bit(kLynxMstErr))
  5332.                     {
  5333.                         pLynxRegs->dmaChannel[dmaChannel].status |= EndianSwapImm32Bit(kLynxMstErr);
  5334.                         SynchronizeIO ();
  5335.                         status = paramErr;        // JKL *** better error?
  5336.                     }
  5337.                     else
  5338.                         status = noErr;            // DMA being stopped is not a error
  5339.                 }
  5340.                 else
  5341.                     status = timeoutErr;        // !!! Proper Error?
  5342.                 break;
  5343.             }
  5344.             else
  5345.             {
  5346.                 timeoutAbsolute =
  5347.                     AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationMillisecond));
  5348.                 patience--;
  5349.             }        
  5350.         }
  5351.     }
  5352.     
  5353.     return status;
  5354. }
  5355.  
  5356.  
  5357. ////////////////////////////////////////////////////////////////////////////////
  5358. //
  5359. // LynxFWIMSetLinkControl
  5360. //
  5361. //   This proc sets the link control register and updates various link control
  5362. // parameters.
  5363. //
  5364. // IMPORTANT! For consistency with other routines I changed the endianness of the
  5365. // linkControl parameter. Now you swap it before calling this function.
  5366. // DCB - 6/4/98
  5367. //
  5368.  
  5369. static OSStatus LynxFWIMSetLinkControl(
  5370.     LynxFWIMDataPtr                pLynxFWIMData,
  5371.     UInt32                        linkControl)
  5372. {
  5373.     LynxRegistersPtr            pLynxRegs;
  5374.     OSStatus                    status = noErr;
  5375.  
  5376.     // Set asyncRxOverflowSetLinkControl in FWIM data.
  5377.     //zzz still have synchronization issues with async receive DMA
  5378.     pLynxFWIMData->asyncRxOverflowSetLinkControl =
  5379.         EndianSwap32Bit (linkControl | kLynxBUSY_CNTRL);
  5380.  
  5381.     // Set linkControl register.
  5382.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5383.     status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  5384.         (UInt32 *) &pLynxRegs->linkControl,
  5385.         (UInt32 ) linkControl );
  5386.     SynchronizeIO ();
  5387.     
  5388.     return status;
  5389. }
  5390.  
  5391. ////////////////////////////////////////////////////////////////////////////////
  5392. //
  5393. // LynxFWIMSetLinkControlBits
  5394. //
  5395. //   Uses the above DMA routines to set some bits in a register field. The
  5396. //   register is read, and the new bits are or'd in and then the register
  5397. //   is written back.
  5398. //
  5399.  
  5400. static OSStatus LynxFWIMSetLinkControlBits (
  5401.     LynxFWIMDataPtr                pLynxFWIMData,
  5402.     UInt32                        linkControl)
  5403. {
  5404.     UInt32                        existingRegisterData;
  5405.     LynxRegistersPtr            pLynxRegs;
  5406.     OSStatus                    status = noErr;
  5407.  
  5408.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5409.  
  5410.     status = LynxFWIMSafeRegisterRead( pLynxFWIMData, (UInt32 *) &pLynxRegs->linkControl, &existingRegisterData);
  5411.  
  5412.     if( !status ) {
  5413.         existingRegisterData |= linkControl;
  5414.         status = LynxFWIMSetLinkControl( pLynxFWIMData, existingRegisterData );
  5415.     }
  5416.  
  5417.     return( status );
  5418. }
  5419.  
  5420. ////////////////////////////////////////////////////////////////////////////////
  5421. //
  5422. // LynxFWIMClearLinkControlBits
  5423. //
  5424. //   Uses the above DMA routines to clear some bits in a register field. The
  5425. //   register is read, and the new bits are and'd with the complement of what
  5426. //   was already there and the result is is written back.
  5427. //
  5428.  
  5429. static OSStatus LynxFWIMClearLinkControlBits (
  5430.     LynxFWIMDataPtr                pLynxFWIMData,
  5431.     UInt32                        linkControl)
  5432. {
  5433.     UInt32                        existingRegisterData;
  5434.     LynxRegistersPtr            pLynxRegs;
  5435.     OSStatus                    status = noErr;
  5436.     
  5437.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5438.  
  5439.     status = LynxFWIMSafeRegisterRead( pLynxFWIMData, (UInt32 *) &pLynxRegs->linkControl, &existingRegisterData);
  5440.  
  5441.     if( !status ) {
  5442.         existingRegisterData &= ~linkControl;
  5443.         status = LynxFWIMSetLinkControl( pLynxFWIMData, existingRegisterData );
  5444.     }
  5445.  
  5446.     return( status );
  5447. }
  5448.  
  5449.  
  5450. ////////////////////////////////////////////////////////////////////////////////
  5451. //
  5452. // LynxFWIMSetAsyncRxComparatorMask1
  5453. //
  5454. //   This proc sets the async receive mask1 comparator and updates some
  5455. // parameters.
  5456. //
  5457.  
  5458. static void LynxFWIMSetAsyncRxComparatorMask1(
  5459.     LynxFWIMDataPtr                pLynxFWIMData,
  5460.     UInt32                        mask1)
  5461. {
  5462.     LynxRegistersPtr            pLynxRegs;
  5463.  
  5464.     // Set asyncRxOverflowSetPCLComparator in FWIM data.
  5465.     //zzz still have synchronization issues with async receive DMA
  5466.     pLynxFWIMData->asyncRxOverflowSetPCLComparator =
  5467.         EndianSwap32Bit (mask1 & ~kLynxEN_CH_COMPARE);
  5468.  
  5469.     // Set comparator register.
  5470.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5471.     
  5472.     LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  5473.                 (UInt32 *) &pLynxRegs->dmaComparator[pLynxFWIMData->asyncRxDMA].mask1,
  5474.                 (UInt32)EndianSwap32Bit (mask1));
  5475.     SynchronizeIO ();
  5476. }
  5477.  
  5478.  
  5479. ////////////////////////////////////////////////////////////////////////////////
  5480. //
  5481. // LynxFWIMWriteATF
  5482. //
  5483. //   Common code for writing an ATF packet
  5484. //
  5485.  
  5486. static OSStatus LynxFWIMWriteATF(
  5487.     LynxFWIMDataPtr                pLynxFWIMData,
  5488.     UInt32                        transmitType,
  5489.     UInt32                        speed,
  5490.     UInt32                        baseCount,        // count [1-4] of quads below:
  5491.     UInt32                        data1,
  5492.     UInt32                        data2,
  5493.     UInt32                        data3,
  5494.     UInt32                        data4,
  5495.     UInt32                        extCount,        // count in BYTES of data below:
  5496.     UInt32                        *extData)
  5497. {
  5498.     LynxRegistersPtr            pLynxRegs;
  5499.     IOPreparationTable            ioPreparationTable;
  5500.     UInt32                        dataBuffer[4];
  5501.     UInt32                        pclControl;
  5502.     OSStatus                    status = noErr;
  5503.  
  5504. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteATF");
  5505.  
  5506.     // Get pointer to link registers.
  5507.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5508.     
  5509.     // Set up data PCL.
  5510.     dataBuffer[0] = data1;
  5511.     dataBuffer[1] = data2;
  5512.     dataBuffer[2] = data3;
  5513.     dataBuffer[3] = data4;
  5514.     pclControl = (transmitType << kLynxDMA_CMDPhase) | kLynxDMA_WAIT_FOR_STATUS;
  5515.     if (speed == kFWSpeed200MBit)
  5516.         pclControl |= kLynxDMA200mbps << kLynxDMA_xmit_spd_codePhase;
  5517.     else if (speed == kFWSpeed400MBit)
  5518.         pclControl |= kLynxDMA400mbps << kLynxDMA_xmit_spd_codePhase;
  5519.     LynxFWIMBuildAsyncTxPCL (pLynxFWIMData,
  5520.                              &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]),
  5521.                              &ioPreparationTable,
  5522.                              pclControl,
  5523.                              (Ptr) &dataBuffer[0],
  5524.                              baseCount * sizeof (UInt32),
  5525.                              (Ptr) extData,
  5526.                              extCount);
  5527.     
  5528.     // Add data PCL to async transmit program and start.
  5529.     LynxFWIMAddAsyncTxPCL (&(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]));
  5530.  
  5531. #if 0
  5532.     // This way is bad.  We hammer the link control register via PCI.
  5533.     // That causes FIFO underflows on big packets.
  5534.     // Wait for async transmit program to end, or TX to be disabled (due to bus reset).
  5535.     //
  5536.     // If this gets turned back on, use safe register access for the linkControl...
  5537.     while ((EndianSwap32Bit(pLynxRegs->linkControl) & kLynxTX_ASYNC_EN) &&
  5538.            !(pLynxFWIMData->asyncTxDoneFlag));
  5539. #endif
  5540.  
  5541.     // This still isn't great.  We should just return, and then handle completion or
  5542.     // failure later, when an interrupt or timer goes off.
  5543.     
  5544.     // Wait for async transmit program to end, or TX to be disabled (due to bus reset).
  5545.     // Check TX disable only once per millisecond.  Try this for at most 50 milliseconds.
  5546.     // !!! What the heck do we do if we timeout?
  5547.  
  5548.  
  5549.     // Wait til pLynxFWIMData->asyncTxDoneFlag == 0xFFFFFFFF
  5550.     status = LynxFWIMWaitAsyncTXFree( pLynxFWIMData, kAsyncTransmitDMA, (UInt32 *)&pLynxFWIMData->asyncTxDoneFlag, 0xFFFFFFFF );
  5551.  
  5552.     // Clean up transmission.
  5553.     CheckpointIO (ioPreparationTable.preparationID, kNilOptions);
  5554.     pLynxFWIMData->pNextAsyncTxPCL =
  5555.         pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDataPCL].pNextPCL;
  5556.         
  5557.  
  5558.     return status;
  5559. }
  5560.  
  5561.  
  5562. ////////////////////////////////////////////////////////////////////////////////
  5563. //
  5564. // LynxFWIMBuildAsyncTxPCL
  5565. //
  5566. //   This proc builds an asynchronous transmit PCL from the given parameters.
  5567. // buffer1 is assumed to be small.  It is usually a packet header.  buffer2 is
  5568. // assumed to be larger and typically is a packet payload.
  5569. //
  5570.  
  5571. static OSStatus    LynxFWIMBuildAsyncTxPCL(
  5572.     LynxFWIMDataPtr                pLynxFWIMData,
  5573.     LynxPCLPtr                    pPCL,
  5574.     IOPreparationTable            *ioPreparationTable,
  5575.     UInt32                        pclControl,
  5576.     Ptr                            buffer1,
  5577.     UInt32                        size1,
  5578.     Ptr                            buffer2,
  5579.     UInt32                        size2)
  5580. {
  5581.     PhysicalAddress                physicalMapping[kMaxBufPage];
  5582.     UInt32                        pageSize,
  5583.                                 pageShift;
  5584.     UInt32                        numPages;
  5585.     Ptr                            preparedBuffer;
  5586.     UInt32                        seg1Size,
  5587.                                 seg2Size,
  5588.                                 seg3Size;
  5589.     UInt32                        seg2AlignSize;
  5590.     UInt32                        transferSize;
  5591.     UInt32                        pclBufferNum;
  5592.     UInt32                        pageNum;
  5593.     OSStatus                    status = noErr;
  5594.  
  5595.     // Get some FWIM parameters.
  5596.     pageSize = pLynxFWIMData->pageSize;
  5597.     pageShift = pLynxFWIMData->pageShift;
  5598.     preparedBuffer = pLynxFWIMData->asyncXmitBuf;
  5599.  
  5600.     // Do initial PCL set up.
  5601.     pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  5602.     pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  5603.     pPCL->status = EndianSwapImm32Bit (0);
  5604.     pPCL->remaining = EndianSwapImm32Bit (0);
  5605.     pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
  5606.  
  5607.     // Set up initial segment sizes, PCL buffer number, and ioPreparationTable.
  5608.     seg1Size = size1;
  5609.     seg2Size = size2;
  5610.     seg3Size = 0;
  5611.     pclBufferNum = 0;
  5612.     ioPreparationTable->preparationID = kInvalidID;
  5613.  
  5614.     // Add buffer1 to our prepared buffer.
  5615.     if (size1 > 0)
  5616.     {
  5617.         BlockCopy (buffer1, preparedBuffer, size1);
  5618.         preparedBuffer += size1;
  5619.     }
  5620.  
  5621.     // Add data from buffer2 to our prepared buffer to 32 byte align second segment.
  5622.     if ((((UInt32) buffer2) & 31) > 0)
  5623.         seg2AlignSize = 32 - (((UInt32) buffer2) & 31);
  5624.     else
  5625.         seg2AlignSize = 0;
  5626.     if (seg2AlignSize > size2)
  5627.         seg2AlignSize = size2;
  5628.     if (seg2AlignSize > 0)
  5629.     {
  5630.         BlockCopy (buffer2, preparedBuffer, seg2AlignSize);
  5631.         preparedBuffer += seg2AlignSize;
  5632.         seg1Size += seg2AlignSize;
  5633.         buffer2 += seg2AlignSize;
  5634.         seg2Size -= seg2AlignSize;
  5635.     }
  5636.  
  5637.     // Add prepared buffer to PCL.
  5638.     pPCL->buffer[pclBufferNum].control = EndianSwap32Bit (pclControl | seg1Size);
  5639.     pPCL->buffer[pclBufferNum].address =
  5640.         (UInt32 *) EndianSwap32Bit ((UInt32) pLynxFWIMData->asyncXmitBufPhys);
  5641.     pclBufferNum++;
  5642.  
  5643.     // Add rest of buffer2 to PCL.
  5644.     if (seg2Size > 0)
  5645.     {
  5646.         // Set up IO preparation table.
  5647.         numPages = ((((UInt32) buffer2) + seg2Size - 1) >> pageShift) -
  5648.                    (((UInt32) buffer2) >> pageShift) + 1;
  5649.         ioPreparationTable->options = kIOLogicalRanges | kIOIsOutput;
  5650.         ioPreparationTable->addressSpace = kCurrentAddressSpaceID;
  5651.         ioPreparationTable->granularity = 0;
  5652.         ioPreparationTable->firstPrepared = 0;
  5653.         ioPreparationTable->mappingEntryCount = numPages;
  5654.         ioPreparationTable->logicalMapping = 0;
  5655.         ioPreparationTable->physicalMapping = physicalMapping;
  5656.         ioPreparationTable->rangeInfo.range.base = buffer2;
  5657.         ioPreparationTable->rangeInfo.range.length = seg2Size;
  5658.  
  5659.         // Prepare.
  5660.         status = PrepareMemoryForIO (ioPreparationTable);
  5661.     /*zzz*/
  5662.         if (status != noErr)
  5663.         {
  5664.             sprintf (debugStr, "PrepareMemoryForIO error %ld", status);
  5665.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5666.         }
  5667.     /*zzz*/
  5668.  
  5669.         // Add pages to PCL.
  5670.         if (status == noErr)
  5671.         {
  5672.             // Compute first page transfer size.
  5673.             if (numPages > 1)
  5674.                 transferSize = pageSize - (((UInt32) buffer2) & (pageSize - 1));
  5675.             else
  5676.                 transferSize = seg2Size;
  5677.  
  5678.             // Add first page to PCL.
  5679.             pPCL->buffer[pclBufferNum].control =
  5680.                 EndianSwap32Bit (pclControl | transferSize);
  5681.             pPCL->buffer[pclBufferNum].address =
  5682.                 (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[0]);
  5683.             pclBufferNum++;
  5684.  
  5685.             // Add rest of pages except last one to PCL.
  5686.             for (pageNum = 1; pageNum < (numPages - 1); pageNum++)
  5687.             {
  5688.                 // Add page to PCL.
  5689.                 pPCL->buffer[pclBufferNum].control =
  5690.                     EndianSwap32Bit (pclControl | pageSize);
  5691.                 pPCL->buffer[pclBufferNum].address =
  5692.                     (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[pageNum]);
  5693.                 pclBufferNum++;
  5694.             }
  5695.  
  5696.             // Add last page to PCL.
  5697.             if (numPages > 1)
  5698.             {
  5699.                 transferSize = (((UInt32) buffer2) + seg2Size) & (pageSize - 1);
  5700.                 pPCL->buffer[pclBufferNum].control =
  5701.                     EndianSwap32Bit (pclControl | transferSize);
  5702.                 pPCL->buffer[pclBufferNum].address =
  5703.                     (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[numPages - 1]);
  5704.                 pclBufferNum++;
  5705.             }
  5706.         }
  5707.     }
  5708.  
  5709.     // Add zero padding to PCL.
  5710.     if (status == noErr)
  5711.     {
  5712.         // Compute amount of zero padding.
  5713.         if ((size2 & 3) > 0)
  5714.         {
  5715.             seg3Size = 4 - (size2 & 3);
  5716.  
  5717.             // Use prepared buffer for zeros.
  5718.             ((UInt32 *) pLynxFWIMData->asyncXmitBuf)[128] = 0;
  5719.  
  5720.             // Add to PCL.
  5721.             pPCL->buffer[pclBufferNum].control =
  5722.                 EndianSwap32Bit (pclControl | seg3Size);
  5723.             pPCL->buffer[pclBufferNum].address =
  5724.                 (UInt32 *) EndianSwap32Bit ((UInt32) (pLynxFWIMData->asyncXmitBufPhys) + 512);
  5725.             pclBufferNum++;
  5726.         }
  5727.     }
  5728.  
  5729.     // Set last buffer.
  5730.     if (status == noErr)
  5731.         pPCL->buffer[pclBufferNum - 1].control |= EndianSwapImm32Bit (kLynxDMA_LAST_BUF);
  5732.  
  5733.     return (status);
  5734. }
  5735.  
  5736.  
  5737. ////////////////////////////////////////////////////////////////////////////////
  5738. //
  5739. // LynxFWIMRead
  5740. //
  5741. //   This proc performs a read transaction on the FireWire bus.
  5742. //   We write the read command, the completion is handled elsewhere
  5743. //   when we get an interrupt for the receipt of the response.
  5744. //zzz what if timer goes off before request goes out???
  5745. //zzz check length against maximum packet size
  5746. //zzz should be set up to get acknowledgement
  5747. //
  5748.  
  5749. static OSStatus    LynxFWIMRead(
  5750.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  5751.     UInt32                        *pCommandAcceptance)
  5752. {
  5753.     FWIMCommandParamsPtr        pFWIMCommandParams;
  5754.     LynxFWIMDataPtr                pLynxFWIMData; 
  5755.     LynxRegistersPtr            pLynxRegs;
  5756.     UInt32                        data1, data2, data3, data4;
  5757.     UInt32                        sourceID;
  5758.     AbsoluteTime                timeoutAbsolute;
  5759.     OSStatus                    status = noErr;
  5760.  
  5761. //    FWDebugStr ((ConstStr255Param) "\p(Lynx) LynxFWIMRead");
  5762.  
  5763.     // Get our internal data.
  5764.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  5765.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  5766.  
  5767.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  5768.     
  5769.     // Set pending command.
  5770.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  5771.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  5772.  
  5773.     // Get pointer to link registers.
  5774.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5775.  
  5776.     if( pLynxFWIMData->phyNotPowered )
  5777.         status = accessErr;     // !!! Proper error?
  5778.     
  5779.     if( !status ) {
  5780.         // already has bit alignment we'll need later...
  5781.         status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  5782.             (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  5783.             (UInt32 *) &sourceID );
  5784.             
  5785.         sourceID = EndianSwap32Bit( sourceID );
  5786.     }
  5787.     
  5788.     // Check if generation is up to date.
  5789.     if( !status ) {
  5790.         if ((!(pLynxFWIMData->generationValid)) ||
  5791.             (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
  5792.         {
  5793.             status = busReconfiguredErr;
  5794.         }
  5795.     }
  5796.  
  5797. // If we wanted to be really clever, we could program up a spare DMA channel to
  5798. // match the sourceID, tCode, and tLabel, causing the response to be DMAed
  5799. // directly into the desired location, skipping an in-memory copy.
  5800.  
  5801. // Warning - it is ESSENTIAL that reads which fail trigger the timeout handler.
  5802. // FSL can't handle reads that just "vanish".  But, rather than go thru the handler,
  5803. // maybe we can return a failure below.
  5804.  
  5805. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMRead - setting timer for failure");
  5806.     // Set a timeout timer.
  5807.     if (status == noErr)
  5808.     {
  5809.         timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
  5810.         status = SetInterruptTimer
  5811.                     (&timeoutAbsolute,
  5812.                      LynxFWIMReadRequestTimeoutHandler,
  5813.                      pFWIMAsynchCommandParams,
  5814.                      &(pLynxFWIMData->requestTimeoutTimerID));
  5815.         if (status == noErr)
  5816.             pLynxFWIMData->requestTimeoutTimerSet = true;
  5817.     }
  5818.  
  5819. // sometimes FSL tries to read from the local node, which won't work.
  5820. // rather than bothering the DMA engine, just let the timeout timer
  5821. // return the error.  (return now - NYI)
  5822.  
  5823.     // Write read request to ATF.
  5824.     if (status == noErr)
  5825.     {
  5826. // Need to send at correct speed (WriteAFT always sends at 100)
  5827.         pLynxFWIMData->transactionLabel =
  5828.             (pLynxFWIMData->transactionLabel + 1) & 0x3F;
  5829.  
  5830.         // Header quad common to quadlet and block:
  5831.         data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
  5832.         data1 |= (pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase);
  5833.         data1 |= (kFWAsynchNew << kFWAsynchRtPhase);
  5834.         
  5835.         // Packet address same for both:
  5836.         data2 = sourceID;
  5837.         data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
  5838.         data3 = pFWIMAsynchCommandParams->addressLo;
  5839.         
  5840.         if (pFWIMAsynchCommandParams->length == 4)
  5841.         { // Quadlet request.
  5842.                         
  5843.             pLynxFWIMData->tCode = kFWTCodeReadQuadlet;
  5844.             data1 |= (kFWTCodeReadQuadlet << kFWPacketTCodePhase);
  5845.  
  5846.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 3, data1, data2, data3, 0, 0, 0);
  5847.         }
  5848.         else
  5849.         { // Block request.
  5850.  
  5851.             pLynxFWIMData->tCode = kFWTCodeReadBlock;
  5852.             data1 |= (kFWTCodeReadBlock << kFWPacketTCodePhase);
  5853.  
  5854.             data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
  5855.             
  5856.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
  5857.         }
  5858.     }
  5859.  
  5860.     // Complete command on error.
  5861.     if (status != noErr)
  5862.     {
  5863.         pLynxFWIMData->pPendingFWIMCommand = nil;
  5864.         FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, status);
  5865.     }
  5866.  
  5867.     // Return command acceptance.
  5868.     //zzz what if we call FWIMCommandIsComplete before returning this???
  5869.     //zzz well, it still works, but will it always?
  5870.     //zzz actually, when we switch to the dispatch table, each routine can return
  5871.     //zzz the appropriate acceptance, so don't worry about it for now.
  5872.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  5873.  
  5874.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  5875.  
  5876.     return (status);
  5877. }
  5878.  
  5879.  
  5880. ////////////////////////////////////////////////////////////////////////////////
  5881. //
  5882. // LynxFWIMReadResponse
  5883. //
  5884. //   This proc sends a read response packet.
  5885. //zzz check length against maximum packet size
  5886. //zzz should be set up to get acknowledgement
  5887. //
  5888.  
  5889. static OSStatus    LynxFWIMReadResponse(
  5890.     FWIMAsynchResponseCommandParamsPtr
  5891.                                 pFWIMAsynchResponseCommandParams,
  5892.     UInt32                        *pCommandAcceptance)
  5893. {
  5894.     FWIMCommandParamsPtr        pFWIMCommandParams;
  5895.     LynxFWIMDataPtr                pLynxFWIMData; 
  5896.     LynxRegistersPtr            pLynxRegs;
  5897.     UInt32                        data1, data2, data4;
  5898.     UInt32                        sourceID;
  5899.     UInt32                        transactionLabel;
  5900.     UInt32                        responseCode;
  5901.     OSStatus                    status = noErr;
  5902.  
  5903.     // Get our internal data.
  5904.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  5905.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  5906.  
  5907.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  5908.  
  5909.     // Set pending command.
  5910.     pLynxFWIMData->pPendingFWIMResponseCommand =
  5911.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  5912.  
  5913.     // Get pointer to link registers.
  5914.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5915.  
  5916.     if( pLynxFWIMData->phyNotPowered )
  5917.         status = accessErr;     // !!! Proper error?
  5918.     
  5919.     if( !status ) {
  5920.         // already has bit alignment we'll need later...
  5921.         status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  5922.             (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  5923.             (UInt32 *) &sourceID );
  5924.             
  5925.         sourceID = EndianSwap32Bit( sourceID );//zzz read out of FWIM data
  5926.     }
  5927.     
  5928.     if( !status ) {
  5929.         // Check if generation is up to date.
  5930.         if ((!(pLynxFWIMData->generationValid)) ||
  5931.             (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
  5932.         {
  5933.             status = busReconfiguredErr;
  5934.         }
  5935.     }
  5936.  
  5937.     // Write read response to ATF.
  5938.     if (status == noErr)
  5939.     {
  5940.         // Compute transaction label and response code.
  5941.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  5942.                             kFWTransactionDescriptorTLabel) >>
  5943.                            kFWTransactionDescriptorTLabelPhase;
  5944.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  5945.                         kFWResponseDataRCode) >>
  5946.                        kFWResponseDataRCodePhase;
  5947.  
  5948.         // packet control header goes in quad 1
  5949.         data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
  5950.         data1 |= transactionLabel << kFWAsynchTLabelPhase;
  5951.         data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  5952.     
  5953.         // packet destination node ID and response code go in quad 2
  5954.         data2 = sourceID;
  5955.         data2 |= responseCode << kFWAsynchRCodePhase;
  5956.     
  5957.         // packet payload goes in quad 4
  5958.         data4 = (*((UInt32 *) pFWIMAsynchResponseCommandParams->buffer));
  5959.     
  5960.         if (pFWIMAsynchResponseCommandParams->length == 4)
  5961.         { // Quadlet request.
  5962.                         
  5963.             data1 |= kFWTCodeReadQuadletResponse << kFWPacketTCodePhase;
  5964.  
  5965.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, 0, 0);
  5966.         }
  5967.         else
  5968.         { // Block request.
  5969.  
  5970.             data1 |= kFWTCodeReadBlockResponse << kFWPacketTCodePhase;
  5971.  
  5972.             data4 = pFWIMAsynchResponseCommandParams->length << kFWAsynchDataLengthPhase;
  5973.             
  5974.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
  5975.         }
  5976.     }
  5977.  
  5978.     // Complete command on error.
  5979.     //zzz assume success for now.  should check ack code for success.
  5980. //zzz    if (status != noErr)
  5981.     {
  5982.         pLynxFWIMData->pPendingFWIMResponseCommand = nil;
  5983.         FWIMCommandIsComplete(pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID, status);
  5984.     }
  5985.  
  5986.     // Return command acceptance.
  5987.     //zzz what if we call FWIMCommandIsComplete before returning this???
  5988.     //zzz well, it still works, but will it always?
  5989.     //zzz actually, when we switch to the dispatch table, each routine can return
  5990.     //zzz the appropriate acceptance, so don't worry about it for now.
  5991.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  5992.  
  5993.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  5994.  
  5995.     return (status);
  5996. }
  5997.  
  5998.  
  5999. ////////////////////////////////////////////////////////////////////////////////
  6000. //
  6001. // LynxFWIMWrite
  6002. //
  6003. //   This proc performs a write transaction on the FireWire bus.
  6004. //zzz what if timer goes off before request goes out??? A: Execute this proc
  6005. //zzz at secondary interrupt level
  6006. //zzz check length against maximum packet size
  6007. //zzz should be set up to get acknowledgement
  6008. //
  6009.  
  6010. static OSStatus    LynxFWIMWriteTimer(
  6011.     void                        *p1,
  6012.     void                        *p2)
  6013. {
  6014.     UInt32                        commandAcceptance;
  6015.     OSStatus                    status = noErr;
  6016.  
  6017.     status = LynxFWIMWrite ((FWIMAsynchCommandParamsPtr) p1, &commandAcceptance);
  6018.     return (status);
  6019. }
  6020.  
  6021. static OSStatus    LynxFWIMWrite(
  6022.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  6023.     UInt32                        *pCommandAcceptance)
  6024. {
  6025.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6026.     LynxFWIMDataPtr                pLynxFWIMData; 
  6027.     LynxRegistersPtr            pLynxRegs;
  6028.     OSStatus                    status = noErr;
  6029.     UInt32                        data1, data2, data3, data4;
  6030.     UInt32                        sourceID;
  6031.  
  6032.     static UInt32 debug = 0;
  6033.  
  6034. //    sprintf (debugStr, "FWIM Write %ld bytes", (long) pFWIMAsynchCommandParams->length);
  6035. //    FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  6036.     
  6037.     // Get our internal data.
  6038.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  6039.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6040.  
  6041.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  6042.     
  6043.     // Set pending command.
  6044.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  6045.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  6046.  
  6047.     // Timer is off.
  6048.     pLynxFWIMData->requestTimeoutTimerSet = false;
  6049.  
  6050.     // Get pointer to link registers.
  6051.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  6052.  
  6053.     if( pLynxFWIMData->phyNotPowered )
  6054.         status = accessErr;     // !!! Proper error?
  6055.     
  6056.     if( !status ) {
  6057.         // Check if generation is up to date.
  6058.         if ((!(pLynxFWIMData->generationValid)) ||
  6059.             (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
  6060.         {
  6061.             status = busReconfiguredErr;
  6062.         }
  6063.     }
  6064.  
  6065.     //zzz need to set a timeout timer in case we get a ack_pending
  6066.  
  6067.     // already has bit alignment we'll need later...
  6068.     status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  6069.         (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  6070.         (UInt32 *) &sourceID );
  6071.         
  6072.     sourceID = EndianSwap32Bit( sourceID );
  6073.  
  6074.     // Write write request to ATF.
  6075.     if (status == noErr)
  6076.     {
  6077.         if (pFWIMAsynchCommandParams->length == 4)
  6078.         { // Quadlet request.
  6079.             // Write packet control header.
  6080.             data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
  6081.  
  6082.             pLynxFWIMData->transactionLabel =
  6083.                 (pLynxFWIMData->transactionLabel + 1) & 0x3F;
  6084.             pLynxFWIMData->tCode = kFWTCodeWriteQuadlet;
  6085.             data1 |= pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase;
  6086.             data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  6087.             data1 |= kFWTCodeWriteQuadlet << kFWPacketTCodePhase;
  6088.  
  6089.             // Write packet address.
  6090.             data2 = sourceID;
  6091.             data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
  6092.             data3 = pFWIMAsynchCommandParams->addressLo;
  6093.  
  6094.             // Write packet payload.
  6095.             data4 = (*((UInt32 *) pFWIMAsynchCommandParams->buffer));
  6096.  
  6097.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
  6098.         }
  6099.         else
  6100.         { // Block request.
  6101.             // Write packet control header.
  6102.             data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
  6103.  
  6104.             pLynxFWIMData->transactionLabel =
  6105.                 (pLynxFWIMData->transactionLabel + 1) & 0x3F;
  6106.             pLynxFWIMData->tCode = kFWTCodeWriteBlock;
  6107.             data1 |= pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase;
  6108.             data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  6109.             data1 |= kFWTCodeWriteBlock << kFWPacketTCodePhase;
  6110.  
  6111.             // Write packet address.
  6112.             data2 = sourceID;
  6113.             data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
  6114.             data3 = pFWIMAsynchCommandParams->addressLo;
  6115.  
  6116.             // Write request length.
  6117.             data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
  6118.  
  6119.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
  6120.                              pFWIMAsynchCommandParams->length,
  6121.                              (UInt32 *) pFWIMAsynchCommandParams->buffer);
  6122.         }
  6123.     }
  6124.  
  6125.     // Complete command on error.
  6126.     if (status != noErr)
  6127.     {
  6128.         pLynxFWIMData->pPendingFWIMCommand = nil;
  6129.         FWIMCommandIsComplete(pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, status);
  6130.     }
  6131.     else
  6132.     {
  6133.         // We no longer take TxRdy interrupt, instead, the status should already be waiting for us.
  6134.         //zzz We probably should take an interrupt.  Other transmit stuff (like isoch) could
  6135.         //zzz be blocking this transmission for relatively long periods of time.
  6136.         LynxFWIMAckSecondaryInterruptHandler
  6137.             (pLynxFWIMData, &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]));
  6138.     }
  6139.  
  6140.     // Return command acceptance.
  6141.     //zzz what if we call FWIMCommandIsComplete before returning this???
  6142.     //zzz well, it still works, but will it always?
  6143.     //zzz actually, when we switch to the dispatch table, each routine can return
  6144.     //zzz the appropriate acceptance, so don't worry about it for now.
  6145.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  6146.  
  6147.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  6148.  
  6149.     return (status);
  6150. }
  6151.  
  6152.  
  6153. ////////////////////////////////////////////////////////////////////////////////
  6154. //
  6155. // LynxFWIMWriteResponse
  6156. //
  6157. //   This proc sends a write response packet.
  6158. //zzz should be set up to get acknowledgement
  6159. //
  6160. //
  6161.  
  6162. static OSStatus    LynxFWIMWriteResponse(
  6163.     FWIMAsynchResponseCommandParamsPtr
  6164.                                 pFWIMAsynchResponseCommandParams,
  6165.     UInt32                        *pCommandAcceptance)
  6166. {
  6167.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6168.     LynxFWIMDataPtr                pLynxFWIMData; 
  6169.     LynxRegistersPtr            pLynxRegs;
  6170.     UInt32                        data1, data2;
  6171.     UInt32                        sourceID;
  6172.     UInt32                        transactionLabel;
  6173.     UInt32                        responseCode;
  6174.     OSStatus                    status = noErr;
  6175.  
  6176.     // Get our internal data.
  6177.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  6178.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6179.  
  6180.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  6181.  
  6182.     // Set pending command.
  6183.     pLynxFWIMData->pPendingFWIMResponseCommand =
  6184.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  6185.  
  6186.     // Get pointer to link registers.
  6187.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  6188.  
  6189.     if( pLynxFWIMData->phyNotPowered )
  6190.         status = accessErr;     // !!! Proper error?
  6191.     
  6192.     if( !status ) {
  6193.         // already has bit alignment we'll need later...
  6194.         status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  6195.             (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  6196.             (UInt32 *) &sourceID );
  6197.             
  6198.         sourceID = EndianSwap32Bit( sourceID );//zzz read out of FWIM data
  6199.     }
  6200.  
  6201.     if( !status ) {
  6202.         // Check if generation is up to date.
  6203.         if ((!(pLynxFWIMData->generationValid)) ||
  6204.             (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
  6205.         {
  6206.             status = busReconfiguredErr;
  6207.         }
  6208.     }
  6209.     
  6210.     // Write write response to ATF.
  6211.     if (status == noErr)
  6212.     {
  6213.         // Compute transaction label and response code.
  6214.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  6215.                             kFWTransactionDescriptorTLabel) >>
  6216.                            kFWTransactionDescriptorTLabelPhase;
  6217.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  6218.                         kFWResponseDataRCode) >>
  6219.                        kFWResponseDataRCodePhase;
  6220.  
  6221.         // packet control header goes in quad 1
  6222.         data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
  6223.         data1 |= kFWTCodeWriteResponse << kFWPacketTCodePhase;
  6224.         data1 |= transactionLabel << kFWAsynchTLabelPhase;
  6225.         data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  6226.     
  6227.         // packet destination node ID and response code go in quad 2
  6228.         data2 = sourceID;
  6229.         data2 |= responseCode << kFWAsynchRCodePhase;
  6230.  
  6231.         LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 3, data1, data2, 0, 0, 0, 0);
  6232.     }
  6233.  
  6234.     // Complete command on error.
  6235.     //zzz assume success for now.  should check ack code for success.
  6236. //zzz if (status != noErr)
  6237.     {
  6238.         pLynxFWIMData->pPendingFWIMResponseCommand = nil;
  6239.         FWIMCommandIsComplete (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID, status);
  6240.     }
  6241.  
  6242.     // Return command acceptance.
  6243.     //zzz what if we call FWIMCommandIsComplete before returning this???
  6244.     //zzz well, it still works, but will it always?
  6245.     //zzz actually, when we switch to the dispatch table, each routine can return
  6246.     //zzz the appropriate acceptance, so don't worry about it for now.
  6247.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  6248.  
  6249.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  6250.  
  6251.     return (status);
  6252. }
  6253.  
  6254.  
  6255. ////////////////////////////////////////////////////////////////////////////////
  6256. //
  6257. // LynxFWIMLock
  6258. //
  6259. //   This proc performs a lock transaction on the FireWire bus.
  6260. //zzz what if timer goes off before request goes out??? A: Execute this proc
  6261. //zzz at secondary interrupt level
  6262. //zzz check length against maximum packet size
  6263. //zzz should be set up to get acknowledgement
  6264. //
  6265.  
  6266. static OSStatus    LynxFWIMLock(
  6267.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  6268.     UInt32                        *pCommandAcceptance)
  6269. {
  6270.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6271.     LynxFWIMDataPtr                pLynxFWIMData; 
  6272.     LynxRegistersPtr            pLynxRegs;
  6273.     UInt32                        data1, data2, data3, data4, sourceID;
  6274.     AbsoluteTime                timeoutAbsolute;
  6275.     OSStatus                    status = noErr;
  6276.  
  6277. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMLock");
  6278.  
  6279.     // Get our internal data.
  6280.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  6281.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6282.  
  6283.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  6284.  
  6285.     // Set pending command.
  6286.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  6287.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  6288.  
  6289.     // Get pointer to link registers.
  6290.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  6291.  
  6292.     if( pLynxFWIMData->phyNotPowered )
  6293.         status = accessErr;     // !!! Proper error?
  6294.     
  6295.     if( !status ) {
  6296.         // Check if generation is up to date.
  6297.         if ((!(pLynxFWIMData->generationValid)) ||
  6298.             (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
  6299.         {
  6300.             status = busReconfiguredErr;
  6301.         }
  6302.     }
  6303.  
  6304.     // Set a timeout timer.
  6305.     if (status == noErr)
  6306.     {
  6307.         timeoutAbsolute =
  6308.             AddAbsoluteToAbsolute (UpTime (),
  6309.                                    DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
  6310.         status = SetInterruptTimer
  6311.                     (&timeoutAbsolute, LynxFWIMLockRequestTimeoutHandler,
  6312.                      pFWIMAsynchCommandParams,
  6313.                      &(pLynxFWIMData->requestTimeoutTimerID));
  6314.         if (status == noErr)
  6315.             pLynxFWIMData->requestTimeoutTimerSet = true;
  6316.     }
  6317.  
  6318.     // send lock request.
  6319.     if (status == noErr)
  6320.     {
  6321.         pLynxFWIMData->transactionLabel =
  6322.             (pLynxFWIMData->transactionLabel + 1) & 0x3F;
  6323.         pLynxFWIMData->tCode = kFWTCodeLock;
  6324.         
  6325.         // Prepare packet control header for block transaction.
  6326.         data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
  6327.         data1 |= (pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase);
  6328.         data1 |= (kFWAsynchNew << kFWAsynchRtPhase);
  6329.         data1 |= (kFWTCodeLock << kFWPacketTCodePhase);
  6330.  
  6331.         // our ID and the target address.
  6332.         status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  6333.             (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  6334.             (UInt32 *) &sourceID );
  6335.             
  6336.         if( !status ) {
  6337.             sourceID = EndianSwap32Bit( sourceID );
  6338.             data2 = sourceID | (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
  6339.             data3 = pFWIMAsynchCommandParams->addressLo;
  6340.     
  6341.             // request length and extended tCode.
  6342.             data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
  6343.             data4 |= 
  6344.                 (pFWIMAsynchCommandParams->extendedTCode & kFWAsynchExtendedTCode) <<
  6345.                 kFWAsynchExtendedTCodePhase;
  6346.     
  6347.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
  6348.                              pFWIMAsynchCommandParams->length,
  6349.                              (UInt32 *) pFWIMAsynchCommandParams->buffer);
  6350.         }
  6351.     }
  6352.  
  6353.     // Complete command on error.
  6354.     if (status != noErr)
  6355.     {
  6356.         pLynxFWIMData->pPendingFWIMCommand = nil;
  6357.         FWIMCommandIsComplete(pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, status);
  6358.     }
  6359.  
  6360.     // Return command acceptance.
  6361.     //zzz what if we call FWIMCommandIsComplete before returning this???
  6362.     //zzz well, it still works, but will it always?
  6363.     //zzz actually, when we switch to the dispatch table, each routine can return
  6364.     //zzz the appropriate acceptance, so don't worry about it for now.
  6365.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  6366.  
  6367.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  6368.  
  6369.     return (status);
  6370. }
  6371.  
  6372.  
  6373. ////////////////////////////////////////////////////////////////////////////////
  6374. //
  6375. // LynxFWIMLockResponse
  6376. //
  6377. //   This proc sends a lock response packet.
  6378. //zzz should be set up to get acknowledgement
  6379. //
  6380.  
  6381. static OSStatus    LynxFWIMLockResponse(
  6382.     FWIMAsynchResponseCommandParamsPtr
  6383.                                 pFWIMAsynchResponseCommandParams,
  6384.     UInt32                        *pCommandAcceptance)
  6385. {
  6386.     FWIMCommandParamsPtr        pFWIMCommandParams;
  6387.     LynxFWIMDataPtr                pLynxFWIMData; 
  6388.     LynxRegistersPtr            pLynxRegs;
  6389.     UInt32                        data1, data2, data4;
  6390.     UInt32                        sourceID;
  6391.     UInt32                        transactionLabel;
  6392.     UInt32                        responseCode;
  6393.     OSStatus                    status = noErr;
  6394.  
  6395.     // Get our internal data.
  6396.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  6397.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  6398.  
  6399.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  6400.  
  6401.     // Set pending command.
  6402.     pLynxFWIMData->pPendingFWIMResponseCommand =
  6403.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  6404.  
  6405.     // Get pointer to link registers.
  6406.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  6407.  
  6408.     if( pLynxFWIMData->phyNotPowered )
  6409.         status = accessErr;     // !!! Proper error?
  6410.     
  6411.     if( !status ) {
  6412.         // already has bit alignment we'll need later...
  6413.         status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  6414.             (UInt32 *) &pLynxRegs->busNumberNodeNumber,
  6415.             (UInt32 *) &sourceID );
  6416.             
  6417.         sourceID = EndianSwap32Bit( sourceID );//zzz read out of FWIM data
  6418.     }
  6419.     
  6420.     if( !status ) {
  6421.         // Check if generation is up to date.
  6422.         if ((!(pLynxFWIMData->generationValid)) ||
  6423.             (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
  6424.         {
  6425.             status = busReconfiguredErr;
  6426.         }
  6427.     }
  6428.  
  6429.     // Write lock response to ATF.
  6430.     if (status == noErr)
  6431.     {
  6432.         // Compute transaction label and response code.
  6433.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  6434.                             kFWTransactionDescriptorTLabel) >>
  6435.                            kFWTransactionDescriptorTLabelPhase;
  6436.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  6437.                         kFWResponseDataRCode) >>
  6438.                        kFWResponseDataRCodePhase;
  6439.  
  6440.         // packet control header goes in quad 1
  6441.         data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
  6442.         data1 |= transactionLabel << kFWAsynchTLabelPhase;
  6443.         data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  6444.         data1 |= kFWTCodeLockResponse << kFWPacketTCodePhase;
  6445.  
  6446.         // packet destination node ID and response code go in quad 2
  6447.         data2 = sourceID;
  6448.         data2 |= responseCode << kFWAsynchRCodePhase;
  6449.  
  6450.         data4 = pFWIMAsynchResponseCommandParams->length << kFWAsynchDataLengthPhase;
  6451.         data4 |= 
  6452.             (pFWIMAsynchResponseCommandParams->extendedTCode & kFWAsynchExtendedTCode) <<
  6453.             kFWAsynchExtendedTCodePhase;
  6454.  
  6455.         LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
  6456.     }
  6457.  
  6458.     // Complete command on error.
  6459.     //zzz assume success for now.  should check ack code for success.
  6460. //zzz    if (status != noErr)
  6461.     {
  6462.         pLynxFWIMData->pPendingFWIMResponseCommand = nil;
  6463.         FWIMCommandIsComplete(pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID, status);
  6464.     }
  6465.  
  6466.     // Return command acceptance.
  6467.     //zzz what if we call FWIMCommandIsComplete before returning this???
  6468.     //zzz well, it still works, but will it always?
  6469.     //zzz actually, when we switch to the dispatch table, each routine can return
  6470.     //zzz the appropriate acceptance, so don't worry about it for now.
  6471.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  6472.  
  6473.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  6474.  
  6475.     return (status);
  6476. }
  6477.  
  6478.  
  6479. ////////////////////////////////////////////////////////////////////////////////
  6480. //
  6481. // LynxFWIMIsCompilableDCLProgram
  6482. //
  6483. //   This routine determines if the given DCL program is compilable.
  6484. //zzz a table and range check may be faster.
  6485. //zzz should do better checking.
  6486. //zzz maybe we should make this determination in a first pass compilation.
  6487. //
  6488.  
  6489. static Boolean    LynxFWIMIsCompilableDCLProgram(
  6490.     DCLProgramID                dclProgramID)
  6491. {
  6492.     DCLCommandPtr                pDCLCommand;
  6493.     Boolean                        isCompilable = true;
  6494.     UInt32                        opcode;
  6495.     OSStatus                    status = noErr;
  6496.     
  6497.     // Get first DCL in program.
  6498.     status = FWGetDCLProgramStart (dclProgramID, &pDCLCommand);
  6499.     if (status != noErr)
  6500.         isCompilable = false;
  6501.  
  6502.     // Check each DCL in program.
  6503.     while ((isCompilable) && (pDCLCommand != nil))
  6504.     {
  6505.         opcode = pDCLCommand->opcode;
  6506.         opcode &= ~kFWDCLOpDynamicFlag;  // We can compile dynamic opcodes.
  6507.         switch (opcode)
  6508.         {
  6509.             case kDCLReceivePacketStartOp :
  6510.                 break;
  6511.  
  6512.             case kDCLReceivePacketOp :
  6513.                 break;
  6514.  
  6515.             case kDCLSendPacketStartOp :
  6516.                 break;
  6517.  
  6518.             case kDCLSendPacketWithHeaderStartOp :
  6519.                 break;
  6520.  
  6521.             case kDCLSendPacketOp :
  6522.                 break;
  6523.  
  6524.             case kDCLCallProcOp :
  6525.                 break;
  6526.  
  6527.             case kDCLJumpOp :
  6528.                 break;
  6529.  
  6530.             case kDCLLabelOp :
  6531.                 break;
  6532.  
  6533.             case kDCLSetTagSyncBitsOp :
  6534.                 break;
  6535.  
  6536.             case kDCLUpdateDCLListOp :
  6537.                 break;
  6538.  
  6539.             case kDCLTimeStampOp :
  6540.                 break;
  6541.  
  6542.             default :
  6543.                 isCompilable = false;
  6544.                 break;
  6545.         }
  6546.         
  6547.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  6548.     }
  6549.  
  6550.     return (isCompilable);
  6551. }
  6552.  
  6553.  
  6554. ////////////////////////////////////////////////////////////////////////////////
  6555. //
  6556. // LynxFWIMPrepareDCLProgramMemory
  6557. //
  6558. //   This routine prepares all buffers used within a DCL program for physical
  6559. //   I/O, and determines the physical addresses.  dclList is the entire program.
  6560. //
  6561.  
  6562. static OSStatus LynxFWIMPrepareDCLProgramMemory(
  6563.     LynxDCLCompilerEngineDataPtr
  6564.                                 pLynxDCLCompilerEngineData,
  6565.     DCLCommandPtr                dclList,
  6566.     UInt32                        dclListLength)
  6567. {
  6568.     DCLCommandPtr                pDCL;
  6569.     DCLTransferPacketPtr        pDCLTransferPacket;
  6570.     IOPreparationTable            *ioPrep;
  6571.     PhysicalAddress                *physAddrs;                // should be PhysicalMappingTablePtr
  6572.     AddressRangeTablePtr        rangeTable;
  6573.     UInt32                        pageSize, pageShift, pageMask, tmp;
  6574.     UInt32                        pageCount, bufferCount;
  6575.     AbsoluteTime                timeNow;
  6576.     OSStatus                    status = noErr;
  6577.     
  6578.     ioPrep = &pLynxDCLCompilerEngineData->ioPrep;
  6579.     pageSize = GetLogicalPageSize ();
  6580.     pageShift = 0;
  6581.     for (tmp = pageSize; tmp = tmp >> 1; pageShift++);            // Sorry...
  6582.     pageMask = ~(pageSize - 1);
  6583.     
  6584.     // This is gross too.  Make sure we don't use stale data in lookups.
  6585.     timeNow = UpTime ();
  6586.     pLynxDCLCompilerEngineData->engineGeneration = AbsoluteToDuration (timeNow);
  6587.     
  6588.     // We will need to allocate a page table.  We don't know how big it needs
  6589.     // to be, but we can wait until just before we PrepareMemoryForIO to do
  6590.     // the allocation (by then we'll know)
  6591.     
  6592.     // We need to allocate a range/length table.  We fill that in before we
  6593.     // call PrepareMemoryForIO, and it has to be linear, so we have to allocate
  6594.     // it all at once.  We need one entry for each buffer in the program.
  6595.     // That's why we take a parameter indicating the program length.
  6596.     // Note if we ever allow scatter/gather buffers in a DCL program, this
  6597.     // will have to change.
  6598.     
  6599.     // We assumed (in LynxFWIMCompileDCLProgram) that each DCL contained a buffer.
  6600.     // Some of them are branches, etc, so an optimization would be to count more
  6601.     // precisely and save a little memory.
  6602.     
  6603.     // Allocate space for rangeTable
  6604.     if (status == noErr)
  6605.     {        
  6606.         rangeTable = (AddressRangeTablePtr)
  6607.             PoolAllocateResident (dclListLength * sizeof (AddressRange), false);
  6608.         if (!rangeTable) status = memFullErr;
  6609.         ioPrep->rangeInfo.multipleRanges.entryCount = 0;
  6610.         // move this below, use local copy
  6611.         ioPrep->rangeInfo.multipleRanges.rangeTable = rangeTable;
  6612.     }    
  6613.  
  6614.     // Gather information about buffers/pointers
  6615.     if (status == noErr)
  6616.     {
  6617.         pDCL = dclList;
  6618.         bufferCount = 0;        // shadow of ioPrep->rangeInfo.multipleRanges.entryCount
  6619.         pageCount = 0;            // count page table size we will need to allocate
  6620.         
  6621.         while (pDCL != nil)
  6622.         {
  6623.             switch (pDCL->opcode & ~kFWDCLOpFlagMask)
  6624.             {
  6625.                 case kDCLReceivePacketStartOp :
  6626.                 case kDCLReceivePacketOp :
  6627.                 case kDCLSendPacketStartOp :
  6628.                 case kDCLSendPacketWithHeaderStartOp :
  6629.                 case kDCLSendPacketOp :
  6630.  
  6631.                     pDCLTransferPacket = (DCLTransferPacketPtr) pDCL;
  6632.                     rangeTable[bufferCount].base = (void *) pDCLTransferPacket->buffer;
  6633.                     rangeTable[bufferCount].length = pDCLTransferPacket->size;
  6634.                     bufferCount++;
  6635.                     
  6636.                     // buffer + size - 1 is addr of last byte in buffer.
  6637.                     // shift that right by pageShift to get page index of end.
  6638.                     // subtract first page index and add one to get total page count.
  6639.                     
  6640.                     pageCount += // (last page - first page) + 1
  6641.                         ((((((UInt32) (pDCLTransferPacket->buffer)) + pDCLTransferPacket->size) - 1) >> pageShift) -
  6642.                             (((UInt32) (pDCLTransferPacket->buffer)) >> pageShift) + 1);
  6643.                     break;
  6644.                     
  6645.                 default : //No buffer or pointer - nothing to do
  6646.                     break;
  6647.             }
  6648.  
  6649.             pDCL = pDCL->pNextDCLCommand;
  6650.         }
  6651.     }
  6652.  
  6653.     // Allocate space for page table
  6654.     if (status == noErr)
  6655.     {
  6656.         physAddrs = PoolAllocateResident (pageCount * sizeof (PhysicalAddress), false);
  6657.         if (!physAddrs)
  6658.         {
  6659.             status = memFullErr;
  6660.             PoolDeallocate ((Ptr) rangeTable);
  6661.         }
  6662.         pLynxDCLCompilerEngineData->physAddrs = physAddrs;
  6663.     }
  6664.     
  6665.     // Prepare memory for I/O
  6666.     if (status == noErr)
  6667.     {
  6668.         ioPrep->options = kIOMultipleRanges | kIOLogicalRanges |
  6669.                           kIOIsInput | kIOIsOutput;
  6670.         ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  6671.         ioPrep->granularity = 0;                                // do it all now
  6672.         ioPrep->firstPrepared = 0;
  6673.         ioPrep->mappingEntryCount = pageCount;                    // we counted exactly
  6674.         ioPrep->logicalMapping = 0;
  6675.         ioPrep->physicalMapping = physAddrs;                    // return list of phys addrs
  6676.         ioPrep->rangeInfo.multipleRanges.entryCount = bufferCount;
  6677.  
  6678.         // CheckpointIO is in _LynxFWIMReleaseIsochPort
  6679.         status = PrepareMemoryForIO (ioPrep);
  6680.         if (status != noErr)
  6681.         {
  6682.             ioPrep->mappingEntryCount = -1;                        // prevents CheckpointIO, kind of a hack
  6683.             PoolDeallocate ((Ptr) rangeTable);
  6684.             PoolDeallocate ((Ptr) physAddrs);
  6685.  
  6686.             sprintf (debugStr, "DCL data PrepMemIO status %ld    page count %ld",
  6687.                      (long) status,
  6688.                      (long) pageCount);
  6689.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  6690.         }
  6691.     }
  6692.     
  6693.     return status;
  6694. }
  6695.  
  6696.  
  6697. ////////////////////////////////////////////////////////////////////////////////
  6698. //
  6699. // LynxFWIMDMapBufferToPhysical
  6700. //
  6701. //   This routine looks up physical addresses for buffers/pointers.
  6702. //     Fills in the passed page table, returns page count (0 if not found)
  6703.  
  6704. static UInt32 LynxFWIMDataMapToPhysical (
  6705.     LynxDCLCompilerEngineDataPtr
  6706.                                 pLynxDCLCompilerEngineData,
  6707.     Ptr                            pBuffer,
  6708.     UInt32                        size,
  6709.     PhysicalMappingTablePtr        returnTable)
  6710. {
  6711.     UInt32                        pageCount = 0, lookCount = 0;
  6712.     static UInt32                rangeLook = 0, pageLook = 0;
  6713.     static UInt32                pageSize = 0, pageShift = 0;
  6714.     static UInt32                cacheEngineGeneration = 0;
  6715.     IOPreparationTable            *ioPrep = &pLynxDCLCompilerEngineData->ioPrep;
  6716.     AddressRangeTablePtr        try;
  6717.     if (!pageSize)
  6718.     {
  6719.         UInt32 tmp;
  6720.         pageSize = GetLogicalPageSize ();
  6721.         for (tmp = pageSize; tmp = tmp >> 1; pageShift++);            // Sorry...
  6722.     }
  6723.     
  6724.     // Look up phys addrs in our prepared table
  6725.     // Return in provided page table
  6726.     
  6727.     // Start lookup from last known point, if we build in order, lookup is fast
  6728.     // Strictly speaking, rangeLook and pageLook should be static to the
  6729.     // engine data, not the whole FWIM, but I don't think we can compile more
  6730.     // than one DCL program at a time anyway.
  6731.     //
  6732.     // Perhaps more importantly, they should be reset if we've rebuilt the ioPrep,
  6733.     // because they may be off the end or otherwise inaccurate.
  6734.     //
  6735.     // I'm not sure this (optimization) works - it still seems sluggish.
  6736.     
  6737.     if (cacheEngineGeneration != pLynxDCLCompilerEngineData->engineGeneration)
  6738.     {
  6739.         cacheEngineGeneration = pLynxDCLCompilerEngineData->engineGeneration;
  6740.         rangeLook = 0;
  6741.         pageLook = 0;
  6742.     }
  6743.     
  6744.     // Repeat until we find it or run out of places to look
  6745.     
  6746.     while ((lookCount < ioPrep->rangeInfo.multipleRanges.entryCount) && (!pageCount))
  6747.     {
  6748.         try = &ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook];
  6749.         
  6750.         // pageCount is number of physAddr entries used by this range
  6751.         // either copy them (found) or skip over them (not found)
  6752.         
  6753.         pageCount = 1 + (((UInt32) try->base + try->length - 1) >> pageShift) -
  6754.                          ((UInt32) try->base >> pageShift);
  6755.                          
  6756.         // require exact match
  6757.         if ((void *) pBuffer == ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook].base)
  6758.         {
  6759.             // Found pages we want.  Copy page table.
  6760.             BlockCopy (&ioPrep->physicalMapping[pageLook],
  6761.                        returnTable,
  6762.                        pageCount * sizeof (PhysicalAddress));
  6763.             pageLook += pageCount;
  6764.         }
  6765.         else
  6766.         {
  6767.             // These aren't the pages we're looking for.  Skip forward.
  6768.             pageLook += pageCount;
  6769.             pageCount = 0;
  6770.         }
  6771.         
  6772.         lookCount++;
  6773.         rangeLook++;
  6774.         if (rangeLook == ioPrep->rangeInfo.multipleRanges.entryCount)
  6775.         {
  6776.             rangeLook = 0;
  6777.             pageLook = 0;
  6778.         }
  6779.     }
  6780.     
  6781.     if (!pageCount)
  6782.         FWDebugStr ((ConstStr255Param) "\pFailed to find buffer!");
  6783.     
  6784.     return pageCount;
  6785. }
  6786.  
  6787.  
  6788. ////////////////////////////////////////////////////////////////////////////////
  6789. //
  6790. // LynxFWIMCompileDCLProgram
  6791. //
  6792. //   This routine compiles the given DCL program into a PCL program.
  6793. //zzz rename this
  6794. //zzz need to convert data endianess (really?  I think Lynx DMA does that)
  6795. //zzz need to set proper speed.
  6796. //
  6797.  
  6798. static OSStatus LynxFWIMCompileDCLProgram(
  6799.     LynxFWIMDataPtr                pLynxFWIMData,
  6800.     DCLProgramID                dclProgramID,
  6801.     UInt32                        pclChannelNum,
  6802.     UInt32                        channelNum,
  6803.     UInt32                        speed)
  6804. {
  6805.     LynxPCLBuildStatePtr        pLynxPCLBuildState = nil;
  6806.     LynxDCLCompilerEngineDataPtr
  6807.                                 pLynxDCLCompilerEngineData = nil;
  6808.     DCLCommandPtr                pDCLCommand,
  6809.                                 dclList;
  6810.     DCLLabel                    waitLoopDCLLabel,
  6811.                                 transmitDCLLabel;
  6812.     DCLCommand                    waitLoopDCLCommand;
  6813.     LynxPCLPtr                    pStartPCL;
  6814.     UInt32                        startEvent,
  6815.                                 startEventState,
  6816.                                 startEventStateMask;
  6817.     UInt32                        dclListLength;
  6818.     OSStatus                    status = noErr;
  6819.  
  6820.     // Create DCL engine data record.
  6821.     pLynxDCLCompilerEngineData = (LynxDCLCompilerEngineDataPtr)
  6822.         PoolAllocateResident (sizeof (LynxDCLCompilerEngineData), true);
  6823.     if (pLynxDCLCompilerEngineData == nil)
  6824.         status = memFullErr;
  6825.         
  6826.     // Initialize interrupt queue.
  6827.     if (status == noErr)
  6828.     {
  6829.         pLynxFWIMData->pDCLInterruptTail[pclChannelNum] = nil;
  6830.         pLynxFWIMData->pDCLLastInterrupt[pclChannelNum] = nil;
  6831.     }
  6832.         
  6833.     // Set compiler notification proc.
  6834.     if (status == noErr)
  6835.     {
  6836.         status = FWSetDCLProgramCompilerNotificationProc
  6837.                     (dclProgramID, LynxFWIMDCLCompilerNotification);
  6838.     }
  6839.  
  6840.     // Get DCL list from program.
  6841.     //zzz should check for error.
  6842.     if (status == noErr)
  6843.     status = FWGetDCLProgramStart (dclProgramID, &dclList);
  6844.  
  6845.     // Clear compiler data in all DCLs, and count them.
  6846.     if (status == noErr)
  6847.     {
  6848.         pDCLCommand = dclList;
  6849.         dclListLength = 0;
  6850.         while (pDCLCommand != nil)
  6851.         {
  6852.             pDCLCommand->compilerData = nil;
  6853.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  6854.             dclListLength++;
  6855.         }
  6856.     }
  6857.  
  6858.     // The plan is to, before compiling, scan the program to locate all data
  6859.     // buffers.  Then we'll prepare VM mappings for them all at once.  Then
  6860.     // during compilation we can look up the logical->physical mappings.
  6861.     //
  6862.     // A complication is that we may receive notification that a running
  6863.     // program has had its buffers changed.  We get a list of changes.  In
  6864.     // that case we need to prepare the new buffers for DMA and change the
  6865.     // pointers in the PCLs, possibly expanding PCLs if there are more
  6866.     // page crossings than before.  (or maybe not)
  6867.     //
  6868.     // When we update buffers, some may be unchanged, so we can't clear the
  6869.     // original PrepareMemoryForIO.  Buffers can be updated repeatedly, and
  6870.     // we could pile up unlimited ioPrep structures.  So we use a brute-force
  6871.     // solution (NYI) and redo the *entire* ioPrep, not just the changed buffers.
  6872.     // Then we can free (CheckpointIO) the original one, and all live buffers
  6873.     // are still covered.  (There is room for optimizations in that process.)
  6874.     //
  6875.     // The first time we prepare memory, we have the luxury that the program
  6876.     // is not running.  When we do updates, the program *is* running.  But maybe
  6877.     // we can use the same code both times, somehow.
  6878.     
  6879.     if (status == noErr)
  6880.         status = LynxFWIMPrepareDCLProgramMemory (pLynxDCLCompilerEngineData,
  6881.                                                   dclList,
  6882.                                                   dclListLength);
  6883.  
  6884.     // Start our PCL program.
  6885.     if (status == noErr)
  6886.     {
  6887.         status = LynxFWIMPCLStart (pLynxFWIMData, &pLynxPCLBuildState, &pStartPCL);
  6888.         
  6889.         if (status == noErr)
  6890.         {
  6891.             pLynxPCLBuildState->pLynxDCLCompilerEngineData = pLynxDCLCompilerEngineData;
  6892.             pLynxPCLBuildState->pclChannelNum = pclChannelNum;
  6893.             pLynxPCLBuildState->isochChannelNum = channelNum;
  6894.             
  6895.             // When we called PCLStart we allocated the first pool of PCLs (physical memory)
  6896.             // make a note of where the isoch packet header is, we'll use that for this program
  6897.  
  6898.             // This is the header's true location and contents.
  6899.             pLynxDCLCompilerEngineData->isochPacketHeaderPtr =
  6900.                 &(pLynxPCLBuildState->pLynxPCLPoolDataList->isochPacketHeader);
  6901.             *(pLynxDCLCompilerEngineData->isochPacketHeaderPtr) =
  6902.                 (kFWTCodeIsochronousBlock << kFWIsochTCodePhase) |
  6903.                 (channelNum << kFWIsochChanNumPhase);
  6904.                 
  6905.             // make note of the physical address
  6906.             pLynxDCLCompilerEngineData->isochPacketHeaderPhys =
  6907.                 pLynxPCLBuildState->pLynxPCLPoolDataList->isochPacketHeaderPhys;
  6908.  
  6909. #ifdef LynxVMDebug
  6910.             if (((Ptr) (pLynxDCLCompilerEngineData->isochPacketHeaderPtr)) !=
  6911.                 ((Ptr) (pLynxDCLCompilerEngineData->isochPacketHeaderPhys)))
  6912.             {
  6913.                 sprintf (debugStr, "Isoch header PTR (A)  logical %08lx != physical %08lx",
  6914.                          (long) pLynxDCLCompilerEngineData->isochPacketHeaderPtr,
  6915.                          (long) pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
  6916.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  6917.             }
  6918. #endif
  6919.         }
  6920.     }
  6921.     
  6922.     // Check if there's a start event for the cycle count.
  6923.     if (status == noErr)
  6924.     {
  6925.         status = FWGetDCLProgramStartEvent
  6926.                     (dclProgramID, &startEvent, &startEventState, &startEventStateMask);
  6927.     }
  6928.     if ((status == noErr) && (startEvent == kFWDCLCycleEvent))
  6929.     {//zzz need to deal with mask including upper 16 bits
  6930.         // Create some DCLs to wait for cycle event.
  6931.         waitLoopDCLLabel.pNextDCLCommand = &waitLoopDCLCommand;
  6932.         waitLoopDCLLabel.compilerData = nil;
  6933.         waitLoopDCLLabel.opcode = kDCLLabelOp;
  6934.     
  6935.         waitLoopDCLCommand.pNextDCLCommand = (DCLCommandPtr) &transmitDCLLabel;
  6936.         waitLoopDCLCommand.compilerData = nil;
  6937.         waitLoopDCLCommand.opcode = kDCLInvalidOp;
  6938.  
  6939.         transmitDCLLabel.pNextDCLCommand = dclList;
  6940.         transmitDCLLabel.compilerData = nil;
  6941.         transmitDCLLabel.opcode = kDCLLabelOp;
  6942.  
  6943.         // Add wait loop label.
  6944.         status = 
  6945.             LynxFWIMAddLabelDCL (pLynxPCLBuildState, (DCLCommandPtr) &waitLoopDCLLabel);
  6946.  
  6947.         // Add a wait for cycle count commands.
  6948.         // We must set up to start filling the cycle before the cycle we want the packet
  6949.         // to go out on.
  6950.         //zzz setting a compare for startEventState - (1 << 12) will only work right
  6951.         //zzz when bit 12 is set in the mask.
  6952.         if (status == noErr)
  6953.         {
  6954.             //This address is already physical, no translation needed
  6955.             status =
  6956.                 LynxFWIMPCLLoadTemp (pLynxPCLBuildState,
  6957.                                      (Ptr) &(pLynxFWIMData->pLynxRegisters->cycleTimer));
  6958.         }
  6959.         if (status == noErr)
  6960.         {
  6961.             status = LynxFWIMPCLCompareTemp16WithMask (pLynxPCLBuildState,
  6962.                                                        startEventState - (1 << 12),
  6963.                                                        startEventStateMask);
  6964.         }
  6965.         if (status == noErr)
  6966.             status = LynxFWIMPCLBranchIfEqual (pLynxPCLBuildState, &transmitDCLLabel);
  6967.         if (status == noErr)
  6968.             status = LynxFWIMPCLJump (pLynxPCLBuildState, &waitLoopDCLLabel, nil);
  6969.  
  6970.         // Add transmit label.
  6971.         if (status == noErr)
  6972.         {
  6973.             status = LynxFWIMAddLabelDCL (pLynxPCLBuildState,
  6974.                                           (DCLCommandPtr) &transmitDCLLabel);
  6975.             
  6976.             // Set ready register to 1 after we exit the wait loop.
  6977.             // We'll stop transmitting if we find ready has been zeroed.
  6978.             
  6979.             status = LynxFWIMPCLStore1 (pLynxPCLBuildState,
  6980.                      (Ptr) &(pLynxFWIMData->pLynxRegisters->dmaChannel[pclChannelNum].ready));
  6981.         }
  6982.     }
  6983.     else
  6984.     {
  6985.         // set ready to 1 if start event is kFWDCLImmediateEvent
  6986.         status = LynxFWIMPCLStore1 (pLynxPCLBuildState,
  6987.                  (Ptr) &(pLynxFWIMData->pLynxRegisters->dmaChannel[pclChannelNum].ready));
  6988.     }
  6989.     
  6990.     // Process all DCLs.
  6991.     pDCLCommand = dclList;
  6992.     while ((pDCLCommand != nil) && (status == noErr))
  6993.     {
  6994.         status = LynxFWIMAddDCL (pLynxPCLBuildState, pDCLCommand);
  6995.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  6996.     }
  6997.     
  6998.     // Fill in DCL engine data record.
  6999.     if (status == noErr)
  7000.     {
  7001.         pLynxDCLCompilerEngineData->pStartPCL = pStartPCL;
  7002.         pLynxDCLCompilerEngineData->pLynxPCLPoolDataList =
  7003.             pLynxPCLBuildState->pLynxPCLPoolDataList;
  7004.         pLynxDCLCompilerEngineData->pLynxFWIMData = pLynxFWIMData;
  7005.     }
  7006.     
  7007.     // Save engine data.
  7008.     if (status == noErr)
  7009.     {
  7010.         status = FWSetDCLProgramEngineData (dclProgramID,
  7011.                                             (UInt32) pLynxDCLCompilerEngineData);
  7012.     }
  7013.     
  7014.     // Clean up on error.
  7015.     if (status != noErr)
  7016.     {
  7017.         // Deallocate PCL pools.
  7018.         if (pLynxPCLBuildState != nil)
  7019.             if (pLynxPCLBuildState->pLynxPCLPoolDataList != nil)
  7020.                 LynxFWIMDeallocatePCLPools (pLynxPCLBuildState->pLynxPCLPoolDataList);
  7021.  
  7022.         // Deallocate engine data.
  7023.         if (pLynxDCLCompilerEngineData != nil)
  7024.             PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData);
  7025.     }
  7026.  
  7027.     // Clean up.
  7028.     if (pLynxPCLBuildState != nil)
  7029.         PoolDeallocate ((Ptr) pLynxPCLBuildState);
  7030.  
  7031.     return (status);
  7032. }
  7033.  
  7034.  
  7035. ////////////////////////////////////////////////////////////////////////////////
  7036. //
  7037. // LynxFWIMAddDCL
  7038. //
  7039. //   This proc adds the given DCL.
  7040. //
  7041.  
  7042. static OSStatus LynxFWIMAddDCL(
  7043.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7044.     DCLCommandPtr                pDCLCommand)
  7045. {
  7046.     UInt32                        opcode;
  7047.     OSStatus                    status = noErr;
  7048.  
  7049.     // Dispatch off of opcode.
  7050.     opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  7051.     switch (opcode)
  7052.     {
  7053.         case kDCLReceivePacketStartOp :
  7054.             if (status == noErr)
  7055.                 status = LynxFWIMAddReceivePacketStartDCL (pLynxPCLBuildState, pDCLCommand);
  7056.             break;
  7057.             
  7058.         case kDCLReceivePacketOp :
  7059.             if (status == noErr)
  7060.                 status = LynxFWIMAddReceivePacketDCL (pLynxPCLBuildState, pDCLCommand);
  7061.             break;
  7062.             
  7063.         case kDCLSendPacketStartOp :
  7064.             if (status == noErr)
  7065.                 status = LynxFWIMAddSendPacketStartDCL (pLynxPCLBuildState, pDCLCommand);
  7066.             break;
  7067.             
  7068.         case kDCLSendPacketWithHeaderStartOp :
  7069.             if (status == noErr)
  7070.             {
  7071.                 status = LynxFWIMAddSendPacketWithHeaderStartDCL
  7072.                             (pLynxPCLBuildState, pDCLCommand);
  7073.             }
  7074.             break;
  7075.             
  7076.         case kDCLSendPacketOp :
  7077.             status = LynxFWIMAddSendPacketDCL (pLynxPCLBuildState, pDCLCommand);
  7078.             break;
  7079.  
  7080.         case kDCLCallProcOp :
  7081.             status = LynxFWIMAddCallProcDCL (pLynxPCLBuildState, pDCLCommand);
  7082.             break;
  7083.  
  7084.         case kDCLJumpOp :
  7085.             status = LynxFWIMAddJumpDCL (pLynxPCLBuildState, pDCLCommand);
  7086.             break;
  7087.  
  7088.         case kDCLLabelOp :
  7089.             status = LynxFWIMAddLabelDCL (pLynxPCLBuildState, pDCLCommand);
  7090.             break;
  7091.  
  7092.         case kDCLSetTagSyncBitsOp :
  7093.             status = LynxFWIMAddSetTagSyncBitsDCL (pLynxPCLBuildState, pDCLCommand);
  7094.             break;
  7095.  
  7096.         case kDCLUpdateDCLListOp :
  7097.             status = LynxFWIMUpdateDCLListDCL (pLynxPCLBuildState, pDCLCommand);
  7098.             break;
  7099.  
  7100.         case kDCLTimeStampOp :
  7101.             status = LynxFWIMTimeStampDCL (pLynxPCLBuildState, pDCLCommand);
  7102.             break;
  7103.  
  7104.         default : //zzz what can we do?
  7105.             break;
  7106.     }
  7107.     
  7108.     return (status);
  7109. }
  7110.  
  7111.  
  7112. ////////////////////////////////////////////////////////////////////////////////
  7113. //
  7114. // LynxFWIMAddReceivePacketStartDCL
  7115. //
  7116. //   This proc adds a receive packet start DCL.
  7117. //zzz need to be able to specify speed.
  7118. //
  7119.  
  7120. static OSStatus LynxFWIMAddReceivePacketStartDCL(
  7121.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7122.     DCLCommandPtr                pDCLCommand)
  7123. {
  7124.     DCLTransferPacketPtr        pDCLTransferPacket;
  7125.     OSStatus                    status = noErr;
  7126.  
  7127.     // Recast DCL command.
  7128.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  7129.     
  7130.     // Start new receive PCL.
  7131.     status = LynxFWIMPCLNewIsochReceive
  7132.                 (pLynxPCLBuildState,
  7133.                  (LynxPCLPtr *) &(pDCLTransferPacket->compilerData),
  7134.                  (UInt32) pDCLTransferPacket,
  7135.                  kLynxDMA100mbps);
  7136.  
  7137.     // Add payload buffer.
  7138.     if (status == noErr)
  7139.     {
  7140.         status = LynxFWIMPCLAddTransferBuffer
  7141.                     (pLynxPCLBuildState,
  7142.                      pDCLTransferPacket->buffer,
  7143.                      pDCLTransferPacket->size,
  7144.                      (Ptr *) &(pDCLTransferPacket->compilerData),
  7145.                      kLynxLogicalBuffer);
  7146.     }
  7147.     
  7148.     return (status);
  7149. }
  7150.  
  7151.  
  7152. ////////////////////////////////////////////////////////////////////////////////
  7153. //
  7154. // LynxFWIMAddReceivePacketDCL
  7155. //
  7156. //   This proc adds a receive packet DCL.
  7157. //
  7158.  
  7159. static OSStatus LynxFWIMAddReceivePacketDCL(
  7160.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7161.     DCLCommandPtr                pDCLCommand)
  7162. {
  7163.     DCLTransferPacketPtr        pDCLTransferPacket;
  7164.     OSStatus                    status = noErr;
  7165.  
  7166.     // Recast DCL command.
  7167.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  7168.     
  7169.     // Add payload buffer.
  7170.     if (status == noErr)
  7171.     {
  7172.         status = LynxFWIMPCLAddTransferBuffer
  7173.                     (pLynxPCLBuildState,
  7174.                      pDCLTransferPacket->buffer,
  7175.                      pDCLTransferPacket->size,
  7176.                      (Ptr *) &(pDCLTransferPacket->compilerData),
  7177.                      kLynxLogicalBuffer);
  7178.     }
  7179.     
  7180.     return (status);
  7181. }
  7182.  
  7183.  
  7184. ////////////////////////////////////////////////////////////////////////////////
  7185. //
  7186. // LynxFWIMAddSendPacketStartDCL
  7187. //
  7188. //   This proc adds a send packet start DCL.
  7189. //zzz need to be able to specify speed.
  7190. //
  7191.  
  7192. static OSStatus LynxFWIMAddSendPacketStartDCL(
  7193.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7194.     DCLCommandPtr                pDCLCommand)
  7195. {
  7196.     DCLTransferPacketPtr        pDCLTransferPacket,
  7197.                                 pDCLTransferPacketStart;
  7198.     UInt32                        packetSize;
  7199.     UInt32                        packetHeader,
  7200.                                 *pPacketHeaderStorage;
  7201.     PhysicalAddress                pPacketHeaderStoragePhys;
  7202.     Ptr                            pIsochPacketHeader;
  7203.     OSStatus                    status = noErr;
  7204.  
  7205.     // Recast DCL command.
  7206.     pDCLTransferPacketStart = (DCLTransferPacketPtr) pDCLCommand;
  7207.  
  7208.     // Compute packet size by adding this and all subsequent send packets.
  7209.     packetSize = pDCLTransferPacketStart->size;
  7210.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacketStart->pNextDCLCommand;
  7211.     while (pDCLTransferPacket != nil)
  7212.     {
  7213.         if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) == kDCLSendPacketOp)
  7214.         {
  7215.             packetSize += pDCLTransferPacket->size;
  7216.             pDCLTransferPacket =
  7217.                 (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
  7218.         }
  7219.         else
  7220.         {
  7221.             pDCLTransferPacket = nil;
  7222.         }
  7223.     }
  7224.     
  7225.     // Start new transmit PCL.
  7226.     status = LynxFWIMPCLNewIsochTransmit
  7227.                 (pLynxPCLBuildState,
  7228.                  (LynxPCLPtr *) &(pDCLTransferPacketStart->compilerData),
  7229.                  (UInt32) pDCLTransferPacketStart,
  7230.                  kLynxDMA100mbps);
  7231.  
  7232.     // Create packet header.
  7233.     if (status == noErr)
  7234.         packetHeader = packetSize << kFWIsochDataLengthPhase;
  7235.     
  7236.     // Allocate storage in PCL for header.
  7237.     if (status == noErr)
  7238.     {
  7239.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, &pPacketHeaderStorage);
  7240.         if (status == noErr)
  7241.             *pPacketHeaderStorage = packetHeader;
  7242.         // Now convert it to a physical address
  7243.         // I sure hope this was allocated in pLynxPCLBuildState->pCurrentPCL
  7244.         // Debug check below might not catch that
  7245.         // You know, maybe it would be better to make LynxFWIMPCLAllocateWord just return the
  7246.         // physical address.  I think we always end up converting anyway.  And it will be correct.
  7247.         pPacketHeaderStoragePhys = (PhysicalAddress)
  7248.             ((UInt32) pLynxPCLBuildState->pCurrentPCL->refCon +
  7249.              ((UInt32) pPacketHeaderStorage - (UInt32) pLynxPCLBuildState->pCurrentPCL));
  7250.  
  7251. #ifdef LynxVMDebug
  7252.         if (((Ptr) (pPacketHeaderStorage)) !=
  7253.             ((Ptr) (pPacketHeaderStoragePhys)))
  7254.         {
  7255.             sprintf (debugStr, "Isoch header PTR (C)  logical %08lx != physical %08lx",
  7256.                      (long) pPacketHeaderStorage,
  7257.                      (long) pPacketHeaderStoragePhys);
  7258.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  7259.         }
  7260. #endif
  7261.     }
  7262.     
  7263.     // Add packet size part of header buffer.
  7264.     if (status == noErr)
  7265.     {
  7266.         status = LynxFWIMPCLAddTransferBuffer
  7267.                     (pLynxPCLBuildState,
  7268.                      (Ptr) pPacketHeaderStoragePhys,
  7269.                      2,
  7270.                      (Ptr *) &(pDCLTransferPacketStart->compilerData),
  7271.                      kLynxPhysicalBuffer);
  7272.     }
  7273.  
  7274.     // Add rest of header buffer.
  7275.     if (status == noErr)
  7276.     {
  7277.         pIsochPacketHeader =
  7278.             (Ptr) (pLynxPCLBuildState->pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
  7279.         status = LynxFWIMPCLAddTransferBuffer
  7280.                     (pLynxPCLBuildState,
  7281.                      pIsochPacketHeader + 2,
  7282.                      2,
  7283.                      nil,
  7284.                      kLynxPhysicalBuffer);
  7285.     }
  7286.     
  7287.     // Add payload buffer.
  7288.     if (status == noErr)
  7289.     {
  7290.         status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
  7291.                                                pDCLTransferPacketStart->buffer,
  7292.                                                pDCLTransferPacketStart->size,
  7293.                                                nil,
  7294.                                                kLynxLogicalBuffer);
  7295.     }
  7296.     
  7297.     return (status);
  7298. }
  7299.  
  7300.  
  7301. ////////////////////////////////////////////////////////////////////////////////
  7302. //
  7303. // LynxFWIMAddSendPacketWithHeaderStartDCL
  7304. //
  7305. //   This proc adds a send packet with header start DCL.
  7306. //zzz need to be able to specify speed.
  7307. //
  7308.  
  7309. static OSStatus LynxFWIMAddSendPacketWithHeaderStartDCL(
  7310.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7311.     DCLCommandPtr                pDCLCommand)
  7312. {
  7313.     DCLTransferPacketPtr        pDCLTransferPacketStart;
  7314.     OSStatus                    status = noErr;
  7315.  
  7316.     // Recast DCL command.
  7317.     pDCLTransferPacketStart = (DCLTransferPacketPtr) pDCLCommand;
  7318.  
  7319.     // Start new transmit PCL.
  7320.     status = LynxFWIMPCLNewIsochTransmit
  7321.                 (pLynxPCLBuildState,
  7322.                  (LynxPCLPtr *) &(pDCLTransferPacketStart->compilerData),
  7323.                  (UInt32) pDCLTransferPacketStart,
  7324.                  kLynxDMA100mbps);
  7325.  
  7326.     // Add buffer.
  7327.     if (status == noErr)
  7328.     {
  7329.         status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
  7330.                                                pDCLTransferPacketStart->buffer,
  7331.                                                pDCLTransferPacketStart->size,
  7332.                                                nil,
  7333.                                                kLynxLogicalBuffer);
  7334.     }
  7335.     
  7336.     return (status);
  7337. }
  7338.  
  7339.  
  7340. ////////////////////////////////////////////////////////////////////////////////
  7341. //
  7342. // LynxFWIMAddSendPacketDCL
  7343. //
  7344. //   This proc adds a send packet DCL.
  7345. //   zzz In case it doesn't get documented anywhere else, the DCL "SendPacket"
  7346. //   actually means send *part* of a packet.  All consecutive SendPackets will
  7347. //   be merged together with the previous SendPacketStart, to form a single packet.
  7348. //   The same is true of ReceivePacket.
  7349. //
  7350.  
  7351. static OSStatus LynxFWIMAddSendPacketDCL(
  7352.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7353.     DCLCommandPtr                pDCLCommand)
  7354. {
  7355.     DCLTransferPacketPtr        pDCLTransferPacket;
  7356.     OSStatus                    status = noErr;
  7357.  
  7358.     // Recast DCL command.
  7359.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  7360.     
  7361.     // Add buffer.
  7362.     status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
  7363.                                            pDCLTransferPacket->buffer,
  7364.                                            pDCLTransferPacket->size,
  7365.                                            (Ptr *) &(pDCLTransferPacket->compilerData),
  7366.                                            kLynxLogicalBuffer);
  7367.  
  7368.     return (status);
  7369. }
  7370.  
  7371.  
  7372. ////////////////////////////////////////////////////////////////////////////////
  7373. //
  7374. // LynxFWIMAddCallProcDCL
  7375. //
  7376. //   This proc adds a call proc DCL.
  7377. //
  7378.  
  7379. static OSStatus LynxFWIMAddCallProcDCL(
  7380.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7381.     DCLCommandPtr                pDCLCommand)
  7382. {
  7383.     OSStatus                    status = noErr;
  7384.     
  7385.     // Add an interrupt PCL.
  7386.     status = LynxFWIMPCLInterrupt (pLynxPCLBuildState,
  7387.                                    pDCLCommand,
  7388.                                    (Ptr *) &(pDCLCommand->compilerData));
  7389.     
  7390.     return (status);
  7391. }
  7392.  
  7393.  
  7394. ////////////////////////////////////////////////////////////////////////////////
  7395. //
  7396. // LynxFWIMAddJumpDCL
  7397. //
  7398. //   This proc adds a jump DCL.
  7399. //
  7400.  
  7401. static OSStatus LynxFWIMAddJumpDCL(
  7402.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7403.     DCLCommandPtr                pDCLCommand)
  7404. {
  7405.     DCLJumpPtr                    pDCLJump;
  7406.     OSStatus                    status = noErr;
  7407.  
  7408.     // Recast DCL command.
  7409.     pDCLJump = (DCLJumpPtr) pDCLCommand;
  7410.  
  7411.     // Add a jump PCL.
  7412.     status = LynxFWIMPCLJump (pLynxPCLBuildState,
  7413.                               pDCLJump->pJumpDCLLabel,
  7414.                               (Ptr *) &(pDCLJump->compilerData));
  7415.  
  7416.     return (status);
  7417. }
  7418.  
  7419.  
  7420. ////////////////////////////////////////////////////////////////////////////////
  7421. //
  7422. // LynxFWIMAddLabelDCL
  7423. //
  7424. //   This proc adds a label DCL.
  7425. //zzz not optimal.
  7426. //
  7427.  
  7428. static OSStatus LynxFWIMAddLabelDCL(
  7429.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7430.     DCLCommandPtr                pDCLCommand)
  7431. {
  7432.     DCLLabelPtr                    pDCLLabel;
  7433.     OSStatus                    status = noErr;
  7434.  
  7435.     // Recast DCL command.
  7436.     pDCLLabel = (DCLLabelPtr) pDCLCommand;
  7437.  
  7438.     // Add a PCL label.
  7439.     status = LynxFWIMPCLLabel (pLynxPCLBuildState, pDCLLabel);
  7440.  
  7441.     // Resolve label.
  7442.     // This is complicated.  If there were no PCL for a label DCL, we would want
  7443.     // to resolve things that point to us (pDCLCommand) to point to the PCL for
  7444.     // the next "real" command (a transmit, or whatever).  But the next DCL has
  7445.     // not yet been compiled, (and it might be another label), so the PCL that we
  7446.     // would really like to point to doesn't exist yet.
  7447.     //
  7448.     // I think that what we do is have a dummy PCL that does correspond to this
  7449.     // label.  That PCL just does a NOP and falls through to the next PCL (which
  7450.     // doesn't exist yet).  That's what LynxFWIMPCLLabel created.  So we waste a
  7451.     // PCL and add a little latency to jumps, because once we jump to this label
  7452.     // we have to fall through at least one dummy PCL before we get any work done.
  7453.     //
  7454.     // A possible future optimization would be to pre-allocate the next non-label
  7455.     // PCL, so that we know where it is and we can jump to it, rather than making
  7456.     // a dummy PCL as the target.  That could be tricky because pre-allocation
  7457.     // could constrain us.
  7458.     //
  7459.     // A possible alternative optimization would be to take the finished PCL
  7460.     // program, and scan through it for jumps to NOPs, and bump them forward to
  7461.     // the next real command.  That could also be tricky if we try to make changes
  7462.     // to the program later, though.
  7463.     
  7464.     if (status == noErr)
  7465.         status = LynxFWIMResolveDCLLabel (pDCLLabel);
  7466.  
  7467.     return (status);
  7468. }
  7469.  
  7470.  
  7471. ////////////////////////////////////////////////////////////////////////////////
  7472. //
  7473. // LynxFWIMAddSetTagSyncBitsDCL
  7474. //
  7475. //   This proc adds a set tag and sync bits DCL.
  7476. //
  7477.  
  7478. static OSStatus LynxFWIMAddSetTagSyncBitsDCL(
  7479.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7480.     DCLCommandPtr                pDCLCommand)
  7481. {
  7482.     DCLSetTagSyncBitsPtr        pDCLSetTagSyncBits;
  7483.     LynxPCLPtr                    pPCL;
  7484.     UInt32                        currentBuffer;
  7485.     UInt32                        *pIsochPacketHeader;
  7486.     OSStatus                    status = noErr;
  7487.  
  7488.     // Recast DCL command.
  7489.     pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) pDCLCommand;
  7490.  
  7491.     // Get current PCL.
  7492.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  7493.  
  7494.     // Make sure we have at least two commands left in PCL.
  7495.     if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 3)) ||
  7496.         ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
  7497.          (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
  7498.     {
  7499.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
  7500.         if (status == noErr)
  7501.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  7502.     }
  7503.     
  7504.     // Store location of PCL.
  7505.     if (status == noErr)
  7506.     {
  7507.         currentBuffer = pLynxPCLBuildState->currentBuffer;
  7508.         pDCLSetTagSyncBits->compilerData = (UInt32) &(pPCL->buffer[currentBuffer]);
  7509.     }
  7510.  
  7511.     // Get allocation for new isochronous packet header.
  7512.     if (status == noErr)
  7513.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, &pIsochPacketHeader);
  7514.  
  7515.     // Set up isochronous packet header.
  7516.     if (status == noErr)
  7517.     {
  7518.         *pIsochPacketHeader =
  7519.             (kFWTCodeIsochronousBlock << kFWIsochTCodePhase) |
  7520.             (pLynxPCLBuildState->isochChannelNum << kFWIsochChanNumPhase) |
  7521.             (pDCLSetTagSyncBits->tagBits << kFWIsochTagPhase) |
  7522.             (pDCLSetTagSyncBits->syncBits << kFWIsochSyPhase);
  7523.     }
  7524.  
  7525.     // Load temp with new header.
  7526.     // Phys addr of allocated word can be derived from PCL base addr
  7527.     if (status == noErr)
  7528.         status = LynxFWIMPCLLoadTemp (pLynxPCLBuildState,
  7529.                                       (Ptr) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL)));
  7530.  
  7531. #ifdef LynxVMDebug
  7532.         if (((Ptr) (pIsochPacketHeader)) !=
  7533.             ((Ptr) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL))))
  7534.         {
  7535.             sprintf (debugStr, "Isoch header PTR (B)  logical %08lx != physical %08lx",
  7536.                      (long) pIsochPacketHeader,
  7537.                      (long) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL)));
  7538.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  7539.         }
  7540. #endif
  7541.  
  7542.     // Store temp to engine data packet header (actually it's hidden in a PCL pool header).
  7543.     if (status == noErr)
  7544.     {
  7545.         pIsochPacketHeader =
  7546.             (pLynxPCLBuildState->pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
  7547.         status = LynxFWIMPCLStoreTemp (pLynxPCLBuildState, (Ptr) pIsochPacketHeader);
  7548.     }
  7549.  
  7550.     return (status);
  7551. }
  7552.  
  7553.  
  7554. ////////////////////////////////////////////////////////////////////////////////
  7555. //
  7556. // LynxFWIMUpdateDCLListDCL
  7557. //
  7558. //   This proc adds a update DCL list DCL.
  7559. //
  7560.  
  7561. static OSStatus LynxFWIMUpdateDCLListDCL(
  7562.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7563.     DCLCommandPtr                pDCLCommand)
  7564. {
  7565.     OSStatus                    status = noErr;
  7566.     
  7567.     // Add an interrupt PCL.
  7568.     status = LynxFWIMPCLInterrupt (pLynxPCLBuildState,
  7569.                                    pDCLCommand,
  7570.                                    (Ptr *) &(pDCLCommand->compilerData));
  7571.     
  7572.     return (status);
  7573. }
  7574.  
  7575.  
  7576. ////////////////////////////////////////////////////////////////////////////////
  7577. //
  7578. // LynxFWIMTimeStampDCL
  7579. //
  7580. //   This proc adds a time stamp DCL.  This will build PCL commands to read the
  7581. // current cycle counter and write it into the PCL command.  The DCL compiler data
  7582. // will point to where the cycle timer is stored in the PCL command.
  7583. //
  7584.  
  7585. static OSStatus LynxFWIMTimeStampDCL(
  7586.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7587.     DCLCommandPtr                pDCLCommand)
  7588. {
  7589.     LynxFWIMDataPtr                pLynxFWIMData;
  7590.     LynxRegistersPtr            pLynxRegs;
  7591.     LynxPCLPtr                    pPCL,
  7592.                                 physPCL;
  7593.     UInt32                        *pPCLTimeStamp;
  7594.     OSStatus                    status = noErr;
  7595.     
  7596.     // Get current PCL.
  7597.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  7598.     
  7599.     // Get Lynx FWIM data and pointer to link registers.
  7600.     pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
  7601.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  7602.  
  7603.     // Make sure we have at least three commands left in PCL.
  7604.     if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 4)) ||
  7605.         ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
  7606.          (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
  7607.     {
  7608.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
  7609.         if (status == noErr)
  7610.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  7611.     }
  7612.     
  7613.     // Allocate word to store time stamp.
  7614.     if (status == noErr)
  7615.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &pPCLTimeStamp);
  7616.  
  7617.     // Save time stamp pointer in compiler data.
  7618.     if (status == noErr)
  7619.         pDCLCommand->compilerData = (UInt32) pPCLTimeStamp;
  7620.  
  7621.     // Add PCL command to read cycle timer register.
  7622.     if (status == noErr)
  7623.     {
  7624.         status = LynxFWIMPCLLoadTemp
  7625.                     (pLynxPCLBuildState, (Ptr) &(pLynxRegs->cycleTimer));
  7626.     }
  7627.  
  7628.     // Add PCL command to write the cycle timer data into the PCL.
  7629.     if (status == noErr)
  7630.     {
  7631.         physPCL = (LynxPCLPtr) pPCL->refCon;  // Get physical address of PCL.
  7632.         status = LynxFWIMPCLStoreTemp
  7633.                     (pLynxPCLBuildState,
  7634.                      (Ptr) ((UInt32) physPCL + ((UInt32) pPCLTimeStamp - (UInt32) pPCL)));
  7635.     }
  7636.  
  7637.     return (status);
  7638. }
  7639.  
  7640.  
  7641. ////////////////////////////////////////////////////////////////////////////////
  7642. //
  7643. // LynxFWIMPCLStart
  7644. //
  7645. //   This proc creates a PCL build state record and a dummy PCL to start the
  7646. // chain.
  7647. //
  7648.  
  7649. static OSStatus    LynxFWIMPCLStart(
  7650.     LynxFWIMDataPtr                pLynxFWIMData,
  7651.     LynxPCLBuildStatePtr        *ppLynxPCLBuildState,
  7652.     LynxPCLPtr                    *ppPCL)
  7653. {
  7654.     LynxPCLBuildStatePtr        pLynxPCLBuildState;
  7655.     LynxPCLPtr                    pPCL;
  7656.     OSStatus                    status = noErr;
  7657.     
  7658.     // Allocate build state record.
  7659.     status = LynxFWIMAllocatePCLBuildState (pLynxFWIMData, &pLynxPCLBuildState);
  7660.     
  7661.     // Allocate start PCL.
  7662.     if (status == noErr)
  7663.         status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
  7664.     
  7665.     // Create start PCL.
  7666.     if (status == noErr)
  7667.     {
  7668.         pPCL->buffer[0].control =
  7669.             EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  7670.     }
  7671.     
  7672.     // Fill in build state record.
  7673.     if (status == noErr)
  7674.     {
  7675.         pLynxPCLBuildState->pLynxFWIMData = pLynxFWIMData;
  7676.         pLynxPCLBuildState->pFirstPCL = pPCL;
  7677.         pLynxPCLBuildState->pCurrentPCL = pPCL;
  7678.         pLynxPCLBuildState->currentBuffer = 0;
  7679.         pLynxPCLBuildState->pclType = kLynxPCLStartType;
  7680.         pLynxPCLBuildState->refCon = 0;
  7681.         pLynxPCLBuildState->interrupt = false;
  7682.     }
  7683.     
  7684.     // Return results.
  7685.     if (status == noErr)
  7686.     {
  7687.         *ppLynxPCLBuildState = pLynxPCLBuildState;
  7688.         *ppPCL = pPCL;
  7689.     }
  7690.     else
  7691.     {
  7692.         *ppLynxPCLBuildState = nil;
  7693.         *ppPCL = nil;
  7694.     }
  7695.     
  7696.     return (status);
  7697. }
  7698.  
  7699.  
  7700. ////////////////////////////////////////////////////////////////////////////////
  7701. //
  7702. // LynxFWIMPCLAllocateWord
  7703. //
  7704. //   This proc allocates a word at the end of the current PCL.
  7705. //   The idea is to create a little storage space where we can keep data.
  7706. //   The space is at the end of the PCL so we don't try to execute it.
  7707. //   We might do a LOAD_TEMP from this location within the PCL (for example).
  7708. //
  7709.  
  7710. static OSStatus    LynxFWIMPCLAllocateWord(
  7711.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7712.     UInt32                        **ppWord)
  7713. {
  7714.     LynxPCLPtr                    pPCL;
  7715.     SInt32                        lastBuffer;
  7716.     UInt32                        bufferAllocationSize;
  7717.     UInt32                        *pWord;
  7718.     OSStatus                    status = noErr;
  7719.     
  7720.     // Get some data out of build state.
  7721.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  7722.     lastBuffer = pLynxPCLBuildState->lastBuffer;
  7723.     bufferAllocationSize = pLynxPCLBuildState->bufferAllocationSize;
  7724.     
  7725.     // Allocate word.  We may have to extend PCL.
  7726.     if ((lastBuffer >= 13) || (bufferAllocationSize >= 2))
  7727.     {
  7728.         lastBuffer--;
  7729.         bufferAllocationSize = 0;
  7730.     }
  7731.     if (lastBuffer < pLynxPCLBuildState->currentBuffer)
  7732.     {
  7733.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, pLynxPCLBuildState->pclType);
  7734.         if (status == noErr)
  7735.         {
  7736.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  7737.             lastBuffer = 12; //zzz should read back and reallocate if LynxFWIMPCLExtend can allocate a word.
  7738.             bufferAllocationSize = 0;
  7739.         }
  7740.     }
  7741.  
  7742.     if (status == noErr)
  7743.     {
  7744.         pWord = ((UInt32 *) (&(pPCL->buffer[lastBuffer].control))) +
  7745.                 (1 - bufferAllocationSize);
  7746.         bufferAllocationSize++;
  7747.     }
  7748.     
  7749.     // Update build state.
  7750.     if (status == noErr)
  7751.     {
  7752.         pLynxPCLBuildState->lastBuffer = lastBuffer;
  7753.         pLynxPCLBuildState->bufferAllocationSize = bufferAllocationSize;
  7754.     }
  7755.     
  7756.     // Return results.
  7757.     if (status == noErr)
  7758.         *ppWord = pWord;
  7759.     else
  7760.         *ppWord = nil;
  7761.     
  7762.     return (status);
  7763. }
  7764.  
  7765.  
  7766. ////////////////////////////////////////////////////////////////////////////////
  7767. //
  7768. // LynxFWIMPCLNew
  7769. //
  7770. //   This proc creates a new logical PCL.
  7771. //
  7772.  
  7773. static OSStatus    LynxFWIMPCLNew(
  7774.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7775.     LynxPCLPtr                    *ppPCL,
  7776.     UInt32                        refCon)
  7777. {
  7778.     LynxFWIMDataPtr                pLynxFWIMData;
  7779.     LynxPCLPtr                    pPCL,
  7780.                                 pPrevPCL;
  7781.     OSStatus                    status = noErr;
  7782.     
  7783.     // Get data from build state.
  7784.     pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
  7785.     pPrevPCL = pLynxPCLBuildState->pCurrentPCL;
  7786.     
  7787.     // Allocate new PCL.
  7788.     status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
  7789.     
  7790.     // Set up PCL.
  7791.     if (status == noErr)
  7792.     {
  7793.         pPCL->buffer[0].control =
  7794.             EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  7795.     }
  7796.     
  7797.     // Link previous PCL.
  7798.     if ((status == noErr) &&
  7799.         (((UInt32) pPrevPCL->nextPCL) == EndianSwapImm32Bit (kLynxCPLINVALID)))
  7800.     {
  7801.         // Elsewhere we check pPCL to see if it's kLynxCPLINVALID before we
  7802.         // dereference it.  But we just allocated pPCL so we know this one's safe.
  7803.         pPrevPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) pPCL->refCon);    // Phys addr
  7804.     }
  7805.  
  7806.     // Update build state.
  7807.     if (status == noErr)
  7808.     {
  7809.         pLynxPCLBuildState->pFirstPCL = pPCL;
  7810.         pLynxPCLBuildState->pCurrentPCL = pPCL;
  7811.         pLynxPCLBuildState->currentBuffer = 0;
  7812.         pLynxPCLBuildState->lastBuffer = 13;
  7813.         pLynxPCLBuildState->bufferAllocationSize = 0;
  7814.         pLynxPCLBuildState->pclType = kLynxPCLUnknownType;
  7815.         // We didn't put refCon in the PCL itself (that space is used for the physical
  7816.         // address), but maybe the copy in the BuildState will be used - so preserve it:
  7817.         pLynxPCLBuildState->refCon = refCon;
  7818.         pLynxPCLBuildState->interrupt = false;
  7819.     }
  7820.     
  7821.     // Return results.
  7822.     if (status == noErr)
  7823.         *ppPCL = pPCL;
  7824.     else
  7825.         *ppPCL = nil;
  7826.     
  7827.     return (status);
  7828. }
  7829.  
  7830.  
  7831. ////////////////////////////////////////////////////////////////////////////////
  7832. //
  7833. // LynxFWIMPCLNewIsochReceive
  7834. //
  7835. //   This proc creates a new logical isochronous receive PCL.
  7836. //zzz should we return PCL ptr?
  7837. //
  7838.  
  7839. static OSStatus    LynxFWIMPCLNewIsochReceive(
  7840.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7841.     LynxPCLPtr                    *ppPCL,
  7842.     UInt32                        refCon,
  7843.     UInt32                        speed)
  7844. {
  7845.     LynxPCLPtr                    pPCL;
  7846.     UInt32                        commandWord;
  7847.     OSStatus                    status = noErr;
  7848.     
  7849.     // Create a new PCL.
  7850.     status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, refCon);
  7851.     
  7852.     // Set pcl type and transfer command word.
  7853.     if (status == noErr)
  7854.     {
  7855.         // Build command word.
  7856.         commandWord = kLynxDMA_RCV << kLynxDMA_CMDPhase;
  7857.         
  7858.         pLynxPCLBuildState->pclType = kLynxPCLTransferType;
  7859.         pLynxPCLBuildState->commandWord = commandWord;
  7860.     }
  7861.     
  7862.     // Return results.
  7863.     if (status == noErr)
  7864.         *ppPCL = pPCL;
  7865.     else
  7866.         *ppPCL = nil;
  7867.     
  7868.     return (status);
  7869. }
  7870.  
  7871.  
  7872. ////////////////////////////////////////////////////////////////////////////////
  7873. //
  7874. // LynxFWIMPCLNewIsochTransmit
  7875. //
  7876. //   This proc creates a new logical isochronous transmit PCL.
  7877. //
  7878.  
  7879. static OSStatus    LynxFWIMPCLNewIsochTransmit(
  7880.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7881.     LynxPCLPtr                    *ppPCL,
  7882.     UInt32                        refCon,
  7883.     UInt32                        speed)
  7884. {
  7885.     LynxPCLPtr                    pPCL;
  7886.     UInt32                        commandWord;
  7887.     OSStatus                    status = noErr;
  7888.     
  7889.     // Create a new PCL.
  7890.     status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, refCon);
  7891.     
  7892.     // Set pcl type and transfer command word.
  7893.     if (status == noErr)
  7894.     {
  7895.         // Build command word.
  7896.         commandWord = kLynxDMA_XMT << kLynxDMA_CMDPhase;
  7897.         commandWord |= speed << kLynxDMA_xmit_spd_codePhase;
  7898.         commandWord |= kLynxDMA_Tramsmit_ISO;
  7899.         
  7900.         // Before sending, "wait" for Ready == 1 Condition.
  7901.         // We actually use this to stop the active sender, between packets.
  7902.         // We never actually wait and then resume.
  7903.         commandWord |= (kLynxDMAWaitReady1 << kLynxDMA_WAIT_SELPhase);
  7904.         
  7905.         pLynxPCLBuildState->pclType = kLynxPCLTransferType;
  7906.         pLynxPCLBuildState->commandWord = commandWord;
  7907.     }
  7908.     
  7909.     // Return results.
  7910.     if (status == noErr)
  7911.         *ppPCL = pPCL;
  7912.     else
  7913.         *ppPCL = nil;
  7914.     
  7915.     return (status);
  7916. }
  7917.  
  7918.  
  7919. ////////////////////////////////////////////////////////////////////////////////
  7920. //
  7921. // LynxFWIMPCLExtend
  7922. //
  7923. //   This proc extends a logical PCL with another physical one.
  7924. //zzz we should probably clear interrupts for previous PCL if interrupts are set
  7925. //
  7926.  
  7927. static OSStatus    LynxFWIMPCLExtend(
  7928.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7929.     UInt32                        pclType)
  7930. {
  7931.     LynxFWIMDataPtr                pLynxFWIMData;
  7932.     LynxPCLPtr                    pPCL,
  7933.                                 pPrevPCL;
  7934.     OSStatus                    status = noErr;
  7935.     
  7936.     // Get data from build state.
  7937.     pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
  7938.     pPrevPCL = pLynxPCLBuildState->pCurrentPCL;
  7939.     
  7940.     // Cannot extend transfer PCLs into another tranfer PCL.
  7941.     if ((pLynxPCLBuildState->pclType == kLynxPCLTransferType) &&
  7942.         (pclType == kLynxPCLTransferType))
  7943.     {
  7944.         status = -1;//zzz what should it really be?
  7945.     }
  7946.     
  7947.     // Allocate new PCL.
  7948.     if (status == noErr)
  7949.         status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
  7950.     
  7951.     // Set up PCL.
  7952.     if (status == noErr)
  7953.     {
  7954.         pPCL->buffer[0].control =
  7955.             EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  7956.     }
  7957.     
  7958.     // Link previous PCL.
  7959.     if ((status == noErr) &&
  7960.         (((UInt32) pPrevPCL->nextPCL) == EndianSwapImm32Bit (kLynxCPLINVALID)))
  7961.     {
  7962.         // No need to check for pPCL == kLynxCPLINVALID, because we just allocated it
  7963.         pPrevPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) pPCL->refCon);    // Phys addr
  7964.     }
  7965.  
  7966.     // Update build state.
  7967.     if (status == noErr)
  7968.     {
  7969.         pLynxPCLBuildState->pCurrentPCL = pPCL;
  7970.         pLynxPCLBuildState->currentBuffer = 0;
  7971.         pLynxPCLBuildState->lastBuffer = 13;
  7972.         pLynxPCLBuildState->bufferAllocationSize = 0;
  7973.         pLynxPCLBuildState->pclType = pclType;
  7974.     }
  7975.     
  7976.     return (status);
  7977. }
  7978.  
  7979.  
  7980. ////////////////////////////////////////////////////////////////////////////////
  7981. //
  7982. // LynxFWIMPCLLoadTemp
  7983. //
  7984. //   This proc adds a load to the temp register command to the PCL program.
  7985. //
  7986.  
  7987. static OSStatus    LynxFWIMPCLLoadTemp(
  7988.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7989.     Ptr                            pSource)
  7990. {
  7991.     OSStatus                    status = noErr;
  7992.     
  7993.     // pSource must by a physical address.
  7994.     // Whoever called us was reponsible for that
  7995.     
  7996.     status = LynxFWIMPCLAuxCommand
  7997.                 (pLynxPCLBuildState,
  7998.                  kLynxDMA_LOAD,
  7999.                  0,
  8000.                  (UInt32) pSource);
  8001.     
  8002.     return (status);
  8003. }
  8004.  
  8005.  
  8006. ////////////////////////////////////////////////////////////////////////////////
  8007. //
  8008. // LynxFWIMPCLStoreTemp
  8009. //
  8010. //   This proc adds a store from the temp register command to the PCL program.
  8011. //
  8012.  
  8013. static OSStatus    LynxFWIMPCLStoreTemp(
  8014.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8015.     Ptr                            pDest)
  8016. {
  8017.     OSStatus                    status = noErr;
  8018.     
  8019.     // pDest must by a physical address.
  8020.     // Whoever called us was reponsible for that
  8021.     
  8022.     status = LynxFWIMPCLAuxCommand
  8023.                 (pLynxPCLBuildState,
  8024.                  kLynxDMA_STORE_QUAD,
  8025.                  0,
  8026.                  (UInt32) pDest);
  8027.     
  8028.     return (status);
  8029. }
  8030.  
  8031.  
  8032. ////////////////////////////////////////////////////////////////////////////////
  8033. //
  8034. // LynxFWIMPCLStore0
  8035. //
  8036. //   This proc adds a store 0 command to the PCL program.
  8037. //
  8038.  
  8039. static OSStatus    LynxFWIMPCLStore0(
  8040.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8041.     Ptr                            pDest)
  8042. {
  8043.     OSStatus                    status = noErr;
  8044.     
  8045.     // pDest must by a physical address.
  8046.     // Whoever called us was reponsible for that
  8047.     
  8048.     status = LynxFWIMPCLAuxCommand
  8049.                 (pLynxPCLBuildState,
  8050.                  kLynxDMA_STORE0,
  8051.                  0,
  8052.                  (UInt32) pDest);
  8053.     
  8054.     return (status);
  8055. }
  8056.  
  8057.  
  8058. ////////////////////////////////////////////////////////////////////////////////
  8059. //
  8060. // LynxFWIMPCLStore1
  8061. //
  8062. //   This proc adds a store 1 command to the PCL program.
  8063. //
  8064.  
  8065. static OSStatus    LynxFWIMPCLStore1(
  8066.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8067.     Ptr                            pDest)
  8068. {
  8069.     OSStatus                    status = noErr;
  8070.     
  8071.     // pDest must by a physical address.
  8072.     // Whoever called us was reponsible for that
  8073.     
  8074.     status = LynxFWIMPCLAuxCommand
  8075.                 (pLynxPCLBuildState,
  8076.                  kLynxDMA_STORE1,
  8077.                  0,
  8078.                  (UInt32) pDest);
  8079.     
  8080.     return (status);
  8081. }
  8082.  
  8083.  
  8084. ////////////////////////////////////////////////////////////////////////////////
  8085. //
  8086. // LynxFWIMPCLCompareTemp16WithMask
  8087. //
  8088. //   This proc adds a 16 bit compare with mask command.
  8089. //
  8090.  
  8091. static OSStatus    LynxFWIMPCLCompareTemp16WithMask(
  8092.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8093.     UInt16                        compareValue,
  8094.     UInt16                        compareMask)
  8095. {
  8096.     OSStatus                    status = noErr;
  8097.     
  8098.     status = LynxFWIMPCLAuxCommand
  8099.                 (pLynxPCLBuildState,
  8100.                  kLynxDMA_COMPARE,
  8101.                  0,
  8102.                  (UInt32) ((compareMask << 16) | compareValue));
  8103.     
  8104.     return (status);
  8105. }
  8106.  
  8107.  
  8108. ////////////////////////////////////////////////////////////////////////////////
  8109. //
  8110. // LynxFWIMPCLBranchIfEqual
  8111. //
  8112. //   This proc adds a branch if equal command.
  8113. //
  8114.  
  8115. static OSStatus    LynxFWIMPCLBranchIfEqual(
  8116.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8117.     DCLLabelPtr                    pDCLLabel)
  8118. {
  8119.     LynxPCLPtr                    pCurrentPCL,
  8120.                                 pDCLLabelPCL;
  8121.     UInt32                        currentBuffer;
  8122.     UInt32                        branchTargetPhys;
  8123.     OSStatus                    status = noErr;
  8124.     
  8125.     // Check if label has been resolved.
  8126.     if ((pDCLLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel)) != nil)
  8127.     {
  8128.         // The label has been resolved, so we can determine the actual
  8129.         // (physical) address of the PCL to jump to.  Put that in the
  8130.         // PCL we are writing, and we're all set.
  8131.         
  8132.         // pDCLLabelPCL can be kLynxCPLINVALID (0x00000001) if the branch
  8133.         // target is a phony DCL (ie stop on condition).  Don't lookup
  8134.         // a physical address for 1.
  8135.         // (Branching to kLynxCPLINVALID will cause the DMA to halt safely.)
  8136.         
  8137.         if (pDCLLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
  8138.             branchTargetPhys = kLynxCPLINVALID;
  8139.             else branchTargetPhys = pDCLLabelPCL->refCon;
  8140.             
  8141.         status = LynxFWIMPCLAuxCommand
  8142.                     (pLynxPCLBuildState,
  8143.                      kLynxDMA_BRANCH,
  8144.                      kLynxAuxConditionDMAReady1,
  8145.                      branchTargetPhys);
  8146.                      
  8147. #ifdef LynxVMDebug
  8148.         if (((Ptr) (pDCLLabelPCL)) !=
  8149.             ((Ptr) (branchTargetPhys)))
  8150.         {
  8151.             sprintf (debugStr, "BranchIfEqual target   logical %08lx != physical %08lx",
  8152.                      (long) pDCLLabelPCL,
  8153.                      (long) branchTargetPhys);
  8154.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  8155.         }
  8156. #endif
  8157.     }
  8158.     else
  8159.     {
  8160.         // The DCL we are jumping to has not yet been compiled into a PCL.
  8161.         // So make a note in the DCL's compilerData of the (logical) address
  8162.         // where the PCL branch target's (physical) address should go.
  8163.         // This will be updated with the target DCL gets compiled.  Note that
  8164.         // compilerData (in the targed DCL) may already contain a reference,
  8165.         // so copy that to our (yet unused) physical target, and replace it
  8166.         // with our own pointer.  This creates a list (of sorts) of references.
  8167.         
  8168.         status = LynxFWIMPCLAuxCommand
  8169.                     (pLynxPCLBuildState,
  8170.                      kLynxDMA_BRANCH,
  8171.                      kLynxAuxConditionDMAReady1,
  8172.                      (UInt32) pDCLLabel->compilerData);
  8173.  
  8174.         // Need to resolve label later.
  8175.         if (status == noErr)
  8176.         {
  8177.             pCurrentPCL = pLynxPCLBuildState->pCurrentPCL;
  8178.             currentBuffer = pLynxPCLBuildState->currentBuffer;
  8179.             
  8180.             // Stash in the target DCL the (logical) address where the
  8181.             // (physical) PCL target will need to go, once it is known.
  8182.             
  8183.             pDCLLabel->compilerData =
  8184.                 (UInt32) &(pCurrentPCL->buffer[currentBuffer - 1].address);
  8185.         }
  8186.     }
  8187.     
  8188.     return (status);
  8189. }
  8190.  
  8191.  
  8192. ////////////////////////////////////////////////////////////////////////////////
  8193. //
  8194. // LynxFWIMPCLJump
  8195. //
  8196. //   This proc sets the current PCL to jump to the given label.
  8197. //zzz we should probably start a new PCL so any subsequent DCLs are not run as
  8198. //zzz a part of the current PCL.
  8199. //
  8200.  
  8201. static OSStatus    LynxFWIMPCLJump(
  8202.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8203.     DCLLabelPtr                    pDCLLabel,
  8204.     Ptr                            *ppPCLCommand)
  8205. {
  8206.     LynxPCLPtr                    pCurrentPCL,
  8207.                                 pDCLLabelPCL;
  8208.     UInt32                        branchTargetPhys;
  8209.     OSStatus                    status = noErr;
  8210.     
  8211.     // Get current PCL.
  8212.     pCurrentPCL = pLynxPCLBuildState->pCurrentPCL;
  8213.     
  8214.     // Return PCL.
  8215.     if (ppPCLCommand != nil)
  8216.         *ppPCLCommand = (Ptr) pCurrentPCL;
  8217.     
  8218.     // Check if label has been resolved.
  8219.     if ((pDCLLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel)) != nil)
  8220.     {
  8221.         // It would be legal to load ->nextPCL with kLynxCPLINVALID.
  8222.         // I don't think that ever happens, but do the right thing if so:
  8223.         
  8224.         if (pDCLLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
  8225.             branchTargetPhys = kLynxCPLINVALID;
  8226.             else branchTargetPhys = pDCLLabelPCL->refCon;
  8227.             
  8228.         pCurrentPCL->nextPCL =
  8229.             (UInt32 *) EndianSwap32Bit (branchTargetPhys);
  8230. #ifdef LynxVMDebug
  8231.         if (((Ptr) (pDCLLabelPCL)) !=
  8232.             ((Ptr) (branchTargetPhys)))
  8233.         {
  8234.             sprintf (debugStr, "Jump target   logical %08lx != physical %08lx",
  8235.                      (long) pDCLLabelPCL,
  8236.                      (long) branchTargetPhys);
  8237.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  8238.         }
  8239. #endif
  8240.     }
  8241.     else
  8242.     {
  8243.         // In case the DCL we're branching to already has one unresolved
  8244.         // reference, store that one in our branch field so we can put our
  8245.         // own address in the DCL.  See next comment.
  8246.         pCurrentPCL->nextPCL =
  8247.             (UInt32 *) EndianSwap32Bit ((UInt32) pDCLLabel->compilerData);
  8248.  
  8249.         // Need to resolve label later.
  8250.         // This is tricky.  Store the (logical) address of the (physical) jump
  8251.         // target address in compilerData.  Later, we'll update it.  Note that
  8252.         // if the spot to be updated contains another address (from previous
  8253.         // line) then we'll update that one too, and so on.
  8254.         pDCLLabel->compilerData = (UInt32) &(pCurrentPCL->nextPCL);
  8255.         
  8256.         // The resolution of all this is done by LynxFWIMResolveDCLLabel.
  8257.         // Labels are resolved as soon as they are added, but we might be
  8258.         // branching to a label that hasn't yet been added (it follows us).
  8259.     }
  8260.     
  8261.     return (status);
  8262. }
  8263.  
  8264.  
  8265. ////////////////////////////////////////////////////////////////////////////////
  8266. //
  8267. // LynxFWIMPCLInterrupt
  8268. //
  8269. //   This proc adds a command to issue an interrupt and add a link to the interrupt queue.
  8270. // This will create a PCL to store the current queue tail into the PCL.  This PCL
  8271. // will then set the queue tail to point into the PCL.
  8272. //
  8273. //   LOAD_TMP
  8274. //     interrupt_queue_tail
  8275. //
  8276. //   STORE_TMP
  8277. //     PCL_queue_link
  8278. //
  8279. //   LOAD_TMP
  8280. //     PCL_queue_link_logical_ptr
  8281. //
  8282. //   STORE_TMP
  8283. //     interrupt_queue_tail
  8284. //
  8285. // PCL_queue_link_logical_ptr: &PCL_queue_link
  8286. // {
  8287. // PCL_queue_link: quad storage
  8288. // DCL_logical_ptr: &DCL
  8289. // } LynxDCLProgramInterruptQueueElement;
  8290. //
  8291.  
  8292. static OSStatus    LynxFWIMPCLInterrupt(
  8293.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8294.     DCLCommandPtr                pDCLCommand,
  8295.     Ptr                            *ppPCLCommand)
  8296. {
  8297.     LynxFWIMDataPtr                pLynxFWIMData,
  8298.                                 physLynxFWIMData;
  8299.     LynxPCLPtr                    pPCL,
  8300.                                 physPCL;
  8301.     DCLCommandPtr                *ppDCLCommand;
  8302.     LynxDCLProgramInterruptQueueElementPtr
  8303.                                 *ppDCLInterruptLink,
  8304.                                 *ppDCLInterrupt;
  8305.     UInt32                        pclChannelNum;
  8306.     UInt32                        currentBuffer;
  8307.     UInt32                        bufferNum;
  8308.     OSStatus                    status = noErr;
  8309.  
  8310.     // Set interrupt flag in build state.
  8311.     pLynxPCLBuildState->interrupt = true;
  8312.     
  8313.     // Get current PCL.
  8314.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  8315.     
  8316.     // Make sure we have at least six commands left in PCL.
  8317.     if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 7)) ||
  8318.         ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
  8319.          (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
  8320.     {
  8321.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
  8322.         if (status == noErr)
  8323.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  8324.     }
  8325.     
  8326.     // Set interrupt bit in preceeding commands.
  8327.     //zzz should only have to do it for first command.
  8328.     if (status == noErr)
  8329.     {
  8330.         currentBuffer = pLynxPCLBuildState->currentBuffer;
  8331.         for (bufferNum = 0; bufferNum < currentBuffer; bufferNum++)
  8332.             pPCL->buffer[bufferNum].control |= EndianSwapImm32Bit (kLynxDMA_INT);
  8333.     }
  8334.  
  8335.     // Return pointer to command.
  8336.     if ((status == noErr) && (ppPCLCommand != nil))
  8337.         *ppPCLCommand = (Ptr) &(pPCL->buffer[currentBuffer]);
  8338.  
  8339.     // Get Lynx FWIM data.
  8340.     pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
  8341.     physLynxFWIMData = (LynxFWIMDataPtr) pLynxFWIMData->fwimDataPhys;
  8342.  
  8343.     // Get physical address of current PCL.
  8344.     physPCL = (LynxPCLPtr) pPCL->refCon;
  8345.     
  8346.     // Allocate a word (DCL_logical_ptr) to hold logical pointer to the DCL.
  8347.     if (status == noErr)
  8348.     {
  8349.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &ppDCLCommand);
  8350.         if (status == noErr)
  8351.             *ppDCLCommand = pDCLCommand;
  8352.     }
  8353.  
  8354.     // Allocate a word (PCL_queue_link) to save interrupt queue link.
  8355.     if (status == noErr)
  8356.     {
  8357.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState,
  8358.                                           (UInt32 **) &ppDCLInterruptLink);
  8359.     }
  8360.  
  8361.     // Allocate a word (PCL_queue_link_logical_ptr) to hold logical pointer to
  8362.     // PCL's LynxDCLProgramInterruptQueueElement.
  8363.     if (status == noErr)
  8364.     {
  8365.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &ppDCLInterrupt);
  8366.         if (status == noErr)
  8367.             *ppDCLInterrupt = (LynxDCLProgramInterruptQueueElementPtr) ppDCLInterruptLink;
  8368.     }
  8369.  
  8370.     // Load the interrupt queue tail.
  8371.     //   LOAD_TMP
  8372.     //     interrupt_queue_tail
  8373.     if (status == noErr)
  8374.     {
  8375.         pclChannelNum = pLynxPCLBuildState->pclChannelNum;
  8376.         status = LynxFWIMPCLLoadTemp
  8377.                     (pLynxPCLBuildState,
  8378.                      (Ptr) &(physLynxFWIMData->pDCLInterruptTail[pclChannelNum]));
  8379.     }
  8380.  
  8381.     // Store the interrupt queue tail into interrupt queue element link.
  8382.     //   STORE_TMP
  8383.     //     PCL_queue_link
  8384.     if (status == noErr)
  8385.     {
  8386.         status =
  8387.             LynxFWIMPCLStoreTemp
  8388.                 (pLynxPCLBuildState,
  8389.                  (Ptr) ((UInt32) physPCL + ((UInt32) ppDCLInterruptLink - (UInt32) pPCL)));
  8390.     }
  8391.  
  8392.     // Load pointer to our interrupt queue element.
  8393.     //   LOAD_TMP
  8394.     //     PCL_queue_link_logical_ptr
  8395.     if (status == noErr)
  8396.     {
  8397.         status =
  8398.             LynxFWIMPCLLoadTemp
  8399.                 (pLynxPCLBuildState,
  8400.                  (Ptr) ((UInt32) physPCL + ((UInt32) ppDCLInterrupt - (UInt32) pPCL)));
  8401.     }
  8402.  
  8403.     // Store pointer to our interrupt queue element into interrupt queue tail.
  8404.     if (status == noErr)
  8405.     {
  8406.         status = LynxFWIMPCLStoreTemp 
  8407.                     (pLynxPCLBuildState,
  8408.                      (Ptr) &(physLynxFWIMData->pDCLInterruptTail[pclChannelNum]));
  8409.     }
  8410.  
  8411.     return (status);
  8412. }
  8413.  
  8414.  
  8415. ////////////////////////////////////////////////////////////////////////////////
  8416. //
  8417. // LynxFWIMPCLAuxCommand
  8418. //
  8419. //   This proc adds the given auxiliary command to the PCL program.
  8420. // Branching is dependent upon the way currentBuffer is set.
  8421. //zzz need to special case if prior PCL was async send
  8422. //
  8423. // In many cases, auxParam is a physical address.  Whoever calls us
  8424. // must have worked it out in advance.
  8425. //
  8426.  
  8427. static OSStatus    LynxFWIMPCLAuxCommand(
  8428.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8429.     UInt32                        auxCommand,
  8430.     UInt32                        waitBranchCondition,
  8431.     UInt32                        auxParam)
  8432. {
  8433.     LynxPCLPtr                    pPCL;
  8434.     UInt32                        pclType;
  8435.     UInt32                        currentBuffer;
  8436.     UInt32                        commandWord;
  8437.     OSStatus                    status = noErr;
  8438.     
  8439.     // Get data from build state.
  8440.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  8441.     pclType = pLynxPCLBuildState->pclType;
  8442.     currentBuffer = pLynxPCLBuildState->currentBuffer;
  8443.     
  8444.     // Check if we need to extend PCL.
  8445.     if (((pclType != kLynxPCLAuxType) &&
  8446.          (pclType != kLynxPCLUnknownType)) ||
  8447.         (currentBuffer == pLynxPCLBuildState->lastBuffer))
  8448.     {
  8449.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
  8450.         if (status == noErr)
  8451.         {
  8452.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  8453.             pclType = kLynxPCLAuxType;
  8454.             currentBuffer = 0;
  8455.         }
  8456.     }
  8457.     
  8458.     // Set PCL type to kLynxPCLAuxType if it's unknown.
  8459.     if ((status == noErr) && (pclType == kLynxPCLUnknownType))
  8460.         pLynxPCLBuildState->pclType = kLynxPCLAuxType;
  8461.     
  8462.     // If we're not on the first command, clear last command last buf bit.
  8463.     if ((status == noErr) && (currentBuffer > 0))
  8464.         pPCL->buffer[currentBuffer - 1].control &= EndianSwapImm32Bit (~kLynxDMA_LAST_BUF);
  8465.  
  8466.     // Add command.
  8467.     if (status == noErr)
  8468.     {
  8469.         // Build command word.
  8470.         commandWord = auxCommand << kLynxDMA_CMDPhase;
  8471.         commandWord |= waitBranchCondition << kLynxDMA_BRANCH_SELPhase;
  8472.         commandWord |= kLynxDMA_LAST_BUF;
  8473.         if (pLynxPCLBuildState->interrupt)
  8474.             commandWord |= kLynxDMA_INT;
  8475.         
  8476.         // Add it.
  8477.         pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
  8478.         // See above - sometimes this is a physical address
  8479.         pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit (auxParam);
  8480.         pLynxPCLBuildState->currentBuffer++;
  8481.     }
  8482.     
  8483.     return (status);
  8484. }
  8485.  
  8486.  
  8487. ////////////////////////////////////////////////////////////////////////////////
  8488. //
  8489. // LynxFWIMPCLAddTransferBuffer
  8490. //
  8491. //   This proc adds the given transfer buffer to the PCL program.  It will
  8492. // return a pointer to the PCL command if ppPCLCommand is non-nil.
  8493. // Branching is dependent upon the way currentBuffer is set.
  8494. //zzz need to special case if prior PCL was async send
  8495. //
  8496.  
  8497. static OSStatus    LynxFWIMPCLAddTransferBuffer(
  8498.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8499.     Ptr                            buffer,
  8500.     UInt32                        bufferSize,
  8501.     Ptr                            *ppPCLCommand,
  8502.     UInt32                        bufferAddrType)
  8503. {
  8504.     LynxPCLPtr                    pPCL;
  8505.     UInt32                        pclType;
  8506.     UInt32                        currentBuffer;
  8507.     UInt32                        commandWord;
  8508.     PhysicalAddress                physAddrs[4];        // enough for 800 mbits
  8509.     UInt32                        pageCount, pageSize, firstPageSize;
  8510.     OSStatus                    status = noErr;
  8511.     
  8512.     // Get data from build state.
  8513.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  8514.     pclType = pLynxPCLBuildState->pclType;
  8515.     currentBuffer = pLynxPCLBuildState->currentBuffer;
  8516.  
  8517.     // Check if we're at the end of the PCL.
  8518.     // Can't transfer accross multiple PCLs.
  8519.     // For now, assume we'll need at most two slots for page crossing.
  8520.     // That handles packets up to 4097 bytes.
  8521.     // At 200 mbits, max isoch packet is 2500.
  8522.     // A 400 mbit channel > 80% reservation can break us.
  8523.     
  8524.     if ((pclType == kLynxPCLTransferType) &&
  8525.         (currentBuffer + 1 >= pLynxPCLBuildState->lastBuffer))
  8526.     {
  8527.         status = -1;//zzz what should it really be?
  8528.         FWDebugStr ((ConstStr255Param) "\pLynxFWIMPCLAddTransferBuffer - failed due to full PCL");
  8529.     }
  8530.     
  8531.     // Check if we need to extend PCL.
  8532.     if ((status == noErr) &&
  8533.         (pclType != kLynxPCLTransferType) &&
  8534.         (pclType != kLynxPCLUnknownType))
  8535.     {
  8536.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLTransferType);
  8537.         if (status == noErr)
  8538.         {
  8539.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  8540.             currentBuffer = 0;
  8541.         }
  8542.     }
  8543.     
  8544.     // Set PCL type to kLynxPCLTransferType if it's unknown.
  8545.     if ((status == noErr) && (pclType == kLynxPCLUnknownType))
  8546.         pLynxPCLBuildState->pclType = kLynxPCLTransferType;
  8547.     
  8548.     // If we're not on the first command, clear last command last buf bit.
  8549.     // Also clear the wait condition on the current command, if transmit.
  8550.     if ((status == noErr) && (currentBuffer > 0))
  8551.     {
  8552.         pPCL->buffer[currentBuffer - 1].control &= EndianSwapImm32Bit (~kLynxDMA_LAST_BUF);
  8553.         
  8554.         // Seems like there ought to be a better way to do this.
  8555.         // Note, duplicated below in page-crossing case
  8556.         if (((pLynxPCLBuildState->commandWord & kLynxDMA_CMD) >> kLynxDMA_CMDPhase) == kLynxDMA_XMT)
  8557.             pLynxPCLBuildState->commandWord &= ~kLynxDMA_WAIT_SEL;
  8558.     }
  8559.     
  8560.     // When VM is turned on, we may have to translate the provided buffer into a physical
  8561.     // address.  If the buffer straddles a page boundary, we may need two (or more)
  8562.     // buffers (>2 buffers only possible at 400 megabits or above).  We built a lookup
  8563.     // table of logical/physical buffers before we started compling, so we use a lookup
  8564.     // function now.  Also note that there can be more than one DCL in this PCL.  For
  8565.     // example, a PacketStart DCL followed by a Packet DCL (for isoch transmit) must be
  8566.     // merged into a single PCL (Lynx allows only one PCL per packet)
  8567.     
  8568.     // Finally, keep in mind that the buffers may be updated later, and the number of
  8569.     // page boundary crossings may change.  But, the upper bound is low - no more than
  8570.     // two crossings at 400 mbits.  However, if the user assembles a transmit packet
  8571.     // out of many small buffers, we don't want to waste slots in the PCL.  Also some
  8572.     // PCL slots may be used up by AUX commands and inline data.
  8573.     
  8574.     // Some buffers are already physical (they point to Lynx registers, PCLs, or other
  8575.     // data we already prepared as physical).
  8576.     
  8577.     // Add command.
  8578.     if (status == noErr)
  8579.     {
  8580.         // Add it.
  8581.         if (bufferAddrType == kLynxPhysicalBuffer)
  8582.         {
  8583.             // If it's a physical buffer, it doesn't matter if we cross page boundaries.
  8584.             // We can do it all with a single transfer command.  (Physical buffers are
  8585.             // usually only 2 (maybe 4) bytes, last I checked.)
  8586.             
  8587.             // Build command word.
  8588.             commandWord = pLynxPCLBuildState->commandWord;
  8589.             commandWord |= bufferSize << kLynxDMA_TransferCountPhase;
  8590.             commandWord |= kLynxDMA_LAST_BUF;
  8591.             pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
  8592.             pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit ((UInt32) buffer);
  8593.  
  8594.             pLynxPCLBuildState->currentBuffer++;
  8595.         }
  8596.         else        // logical buffer
  8597.         {
  8598.             pageCount = LynxFWIMDataMapToPhysical (pLynxPCLBuildState->pLynxDCLCompilerEngineData,
  8599.                                                    buffer, bufferSize, physAddrs);
  8600. #ifdef LynxVMDebug
  8601.             if (((Ptr) (buffer)) !=
  8602.                 ((Ptr) (physAddrs[0])))
  8603.             {
  8604.                 sprintf (debugStr, "Payload lookup   logical %08lx != physical %08lx",
  8605.                          (long) buffer,
  8606.                          (long) physAddrs[0]);
  8607.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  8608.             }
  8609. #endif
  8610.             if (pageCount > 2)
  8611.                 FWDebugStr ((ConstStr255Param) "\pOops, too many pages for DMA (?!)");
  8612.  
  8613.             // Should cache this or make lookup figure it all out for us
  8614.             pageSize = GetLogicalPageSize ();
  8615.             
  8616.             // Make this all work regardless of page size and speed.  Who knows what might change.
  8617.             if (pageCount == 1)
  8618.                 firstPageSize = bufferSize;
  8619.             else
  8620.                 firstPageSize = pageSize - ((UInt32) buffer & (pageSize - 1));
  8621.             
  8622.             // Build command word.
  8623.             commandWord = pLynxPCLBuildState->commandWord;
  8624.             commandWord |= firstPageSize << kLynxDMA_TransferCountPhase;
  8625.             if (pageCount == 1) commandWord |= kLynxDMA_LAST_BUF;
  8626.             pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
  8627.             pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit ((UInt32) physAddrs[0]);
  8628.  
  8629.             // We are now mid-packet.  Clear wait from here to end of packet.
  8630.             // (duplicated above)
  8631.             if (((pLynxPCLBuildState->commandWord & kLynxDMA_CMD) >> kLynxDMA_CMDPhase) == kLynxDMA_XMT)
  8632.                 pLynxPCLBuildState->commandWord &= ~kLynxDMA_WAIT_SEL;
  8633.  
  8634.             if (pageCount > 1)        // assume it's 2
  8635.             {
  8636.                 // Build command word.
  8637.                 commandWord = pLynxPCLBuildState->commandWord;
  8638.                 commandWord |= (bufferSize - firstPageSize) << kLynxDMA_TransferCountPhase;
  8639.                 commandWord |= kLynxDMA_LAST_BUF;
  8640.                 pPCL->buffer[currentBuffer + 1].control = EndianSwap32Bit (commandWord);
  8641.                 pPCL->buffer[currentBuffer + 1].address = (UInt32 *) EndianSwap32Bit ((UInt32) physAddrs[1]);
  8642.             }
  8643.             
  8644.             pLynxPCLBuildState->currentBuffer += pageCount;
  8645.         }
  8646.         
  8647.         // Return pointer to command.
  8648.         if (ppPCLCommand != nil)
  8649.             *ppPCLCommand = (Ptr) &(pPCL->buffer[currentBuffer]);
  8650.  
  8651.     }
  8652.     
  8653.     return (status);
  8654. }
  8655.  
  8656.  
  8657. ////////////////////////////////////////////////////////////////////////////////
  8658. //
  8659. // LynxFWIMResolveDCLLabel
  8660. //
  8661. //   This proc resolves the given DCL label.
  8662. //
  8663.  
  8664. static OSStatus    LynxFWIMResolveDCLLabel(
  8665.     DCLLabelPtr                    pDCLLabel)
  8666. {
  8667.     DCLCommandPtr                pDCLCommand;
  8668.     LynxPCLPtr                    pPCL,
  8669.                                 *pLabelDependency,
  8670.                                 *pNextLabelDependency;
  8671.     UInt32                        branchTargetPhys;
  8672.     OSStatus                    status = noErr;
  8673.     
  8674.     // The label pDCLLabel has just been added to the PCL program.  It may already
  8675.     // be the branch target of one or more existing PCLs.  If so, they have stashed
  8676.     // a pointer to where they hold their branch target in pDCLLabel->compilerData.
  8677.     // Furthermore, if what is pointed to is not nil, it is another pointer to an
  8678.     // unresolved label, etc.  So we follow that chain, filling in our real PCL
  8679.     // address.  Note that we will need to fill in the physical address, since now
  8680.     // is the final stage in assigning jump addresses.
  8681.     
  8682.     // Resolve all of the dependencies.
  8683.     if (pDCLLabel->compilerData != nil)
  8684.     {
  8685.         // Get PCL for this label.
  8686.         // PCL will be the PCL for the next non label DCL.
  8687.         //zzz what if label DCL is last in list???
  8688.         pDCLCommand = pDCLLabel->pNextDCLCommand;
  8689.         while ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
  8690.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  8691.         pPCL = LynxFWIMGetPCLFromDCL (pDCLCommand);
  8692.         
  8693.         // Resolve label to this PCL.
  8694.         if (pPCL != nil)
  8695.         {
  8696.             pLabelDependency = (LynxPCLPtr *) pDCLLabel->compilerData;
  8697.             while (pLabelDependency != nil)
  8698.             {
  8699.                 // Sometimes we branch to kLynxCPLINVALID in order to stop the DMA.
  8700.                 // I'm not sure if that can happen here, but just in case, check
  8701.                 // pPCL for kLynxCPLINVALID before dereferencing it.
  8702.                 
  8703.                 if (pPCL == (LynxPCLPtr) kLynxCPLINVALID)
  8704.                     branchTargetPhys = kLynxCPLINVALID;
  8705.                     else branchTargetPhys = pPCL->refCon;
  8706.                     
  8707.                 pNextLabelDependency = (LynxPCLPtr *) *pLabelDependency;
  8708.                 *pLabelDependency = (LynxPCLPtr) EndianSwap32Bit (branchTargetPhys);
  8709.                 pLabelDependency = pNextLabelDependency;
  8710. #ifdef LynxVMDebug
  8711.                 if (((Ptr) (pPCL)) !=
  8712.                     ((Ptr) (branchTargetPhys)))
  8713.                 {
  8714.                     sprintf (debugStr, "Resolved target   logical %08lx != physical %08lx",
  8715.                              (long) pPCL,
  8716.                              (long) branchTargetPhys);
  8717.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  8718.                 }
  8719. #endif
  8720.             }
  8721.         }
  8722.         pDCLLabel->compilerData = nil;
  8723.     }
  8724.     
  8725.     return (status);
  8726. }
  8727.  
  8728.  
  8729. ////////////////////////////////////////////////////////////////////////////////
  8730. //
  8731. // LynxFWIMGetDCLLabelPCLPtr
  8732. //
  8733. //   This proc returns a pointer to the PCL corresponding to the given label
  8734. // if the given label is resolved.  A return value of nil means the label has
  8735. // not been resolved.
  8736. //
  8737.  
  8738. static LynxPCLPtr    LynxFWIMGetDCLLabelPCLPtr(
  8739.     DCLLabelPtr                    pDCLLabel)
  8740. {
  8741.     DCLCommandPtr                pDCLCommand;
  8742.     LynxPCLPtr                    pDCLLabelPCL;
  8743.  
  8744.     // Search for next command that is not another label.
  8745.     pDCLCommand = pDCLLabel->pNextDCLCommand;
  8746.     while (pDCLCommand != nil)
  8747.     {
  8748.         if ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
  8749.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  8750.         else
  8751.             break;
  8752.     }
  8753.  
  8754.     // Return results.
  8755.     if (pDCLCommand != nil)
  8756.         pDCLLabelPCL = LynxFWIMGetPCLFromDCL (pDCLCommand);
  8757.     else
  8758.         pDCLLabelPCL = (LynxPCLPtr) kLynxCPLINVALID;
  8759.  
  8760.     return (pDCLLabelPCL);
  8761. }
  8762.  
  8763.  
  8764. ////////////////////////////////////////////////////////////////////////////////
  8765. //
  8766. // LynxFWIMPCLLabel
  8767. //
  8768. //   This proc adds a DCL label to the PCL program.
  8769. //
  8770.  
  8771. static OSStatus    LynxFWIMPCLLabel(
  8772.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  8773.     DCLLabelPtr                    pDCLLabel)
  8774. {
  8775.     DCLCommandPtr                pDCLCommand;
  8776.     LynxPCLPtr                    pPCL;
  8777.     OSStatus                    status = noErr;
  8778.  
  8779.     // We don't need to do anything if this label already has a PCL associated
  8780.     // with it.
  8781.     if (LynxFWIMGetDCLLabelPCLPtr (pDCLLabel) == nil)
  8782.     {
  8783.         // Start new PCL.
  8784.         status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, (UInt32) pDCLLabel);
  8785.  
  8786.         // Set next non label DCL's compiler data to the new PCL.
  8787.         // When the next non label DCL is compiled, its compiler data will be updated
  8788.         // to point to the PCL command within the PCL created above.
  8789.         //zzz what if label is last in program?
  8790.         if (status == noErr)
  8791.         {
  8792.             pDCLCommand = pDCLLabel->pNextDCLCommand;
  8793.             while ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
  8794.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  8795.             pDCLCommand->compilerData = (UInt32) pPCL;
  8796.         }
  8797.     }
  8798.  
  8799.     return (status);
  8800. }
  8801.  
  8802.  
  8803. ////////////////////////////////////////////////////////////////////////////////
  8804. //
  8805. // LynxFWIMGetPCLFromDCL
  8806. //
  8807. //   This proc returns a pointer to the start of the PCL corresponding to the
  8808. // given DCL.  Label DCLs do not have corresponding PCLs.
  8809. //zzz well, label DCLs do, so maybe we should integrate LynxFWIMGetDCLLabelPCLPtr
  8810. //zzz with this routine
  8811. //
  8812.  
  8813. static LynxPCLPtr    LynxFWIMGetPCLFromDCL(
  8814.     DCLCommandPtr                pDCLCommand)
  8815. {
  8816.     LynxPCLPtr                    pPCL;
  8817.     
  8818.     // Base of PCL is the compiler data masked with kPCLAlignmentMask.
  8819.     pPCL = (LynxPCLPtr) (pDCLCommand->compilerData & kPCLAlignmentMask);
  8820.     
  8821.     // I have a lingering suspicion that I might have done something wrong
  8822.     // here that can (rarely) cause a physical PCL pointer to get dereferenced.
  8823.     // But I only saw it happen once and I wasn't really paying attention,
  8824.     // so maybe it was just a fluke.
  8825.     
  8826.     return (pPCL);
  8827. }
  8828.  
  8829.  
  8830. ////////////////////////////////////////////////////////////////////////////////
  8831. //
  8832. // LynxFWIMDCLCompilerNotification
  8833. //
  8834. //   This proc handles update notifications for the DCL to PCL compiler.
  8835. //
  8836.  
  8837. static OSStatus        LynxFWIMDCLCompilerNotification(
  8838.     DCLProgramID                dclProgramID,
  8839.     UInt32                        notificationType,
  8840.     DCLCommandPtr                *dclCommandList,
  8841.     UInt32                        numDCLCommands)
  8842. {
  8843.     OSStatus                    status = noErr;
  8844.  
  8845.     switch (notificationType)
  8846.     {
  8847.         case kFWDCLUpdateNotification :
  8848.             status = LynxFWIMDCLCompilerUpdateNotification (dclProgramID,
  8849.                                                             dclCommandList,
  8850.                                                             numDCLCommands);
  8851.             break;
  8852.  
  8853.         case kFWDCLModifyNotification :
  8854.             status = LynxFWIMDCLCompilerModifyNotification (dclProgramID,
  8855.                                                             dclCommandList,
  8856.                                                             numDCLCommands);
  8857.             break;
  8858.  
  8859.         default :
  8860.             status = paramErr;
  8861.             break;
  8862.     }
  8863.  
  8864.     return (status);
  8865. }
  8866.  
  8867.  
  8868. ////////////////////////////////////////////////////////////////////////////////
  8869. //
  8870. // LynxFWIMDCLCompilerUpdateNotification
  8871. //
  8872. //   This proc handles update notifications for the DCL to PCL compiler.  This will
  8873. // do any neccessary CheckPointIOs and update any DCL status fields.
  8874. //zzz do the right stuff in here
  8875. //
  8876.  
  8877. static OSStatus        LynxFWIMDCLCompilerUpdateNotification(
  8878.     DCLProgramID                dclProgramID,
  8879.     DCLCommandPtr                *dclCommandList,
  8880.     UInt32                        numDCLCommands)
  8881. {
  8882.     DCLCommandPtr                pDCLCommand;
  8883.     UInt32                        dclCommandNum;
  8884.     OSStatus                    status = noErr;
  8885.  
  8886.     for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
  8887.     {
  8888.         pDCLCommand = dclCommandList[dclCommandNum];
  8889.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  8890.         {
  8891.             case kDCLTimeStampOp :
  8892.                 LynxFWIMUpdateDCLTimeStamp (pDCLCommand);
  8893.                 break;
  8894.  
  8895.             default :
  8896.                 break;
  8897.         }
  8898.     }
  8899.  
  8900.     return (status);
  8901. }
  8902.  
  8903.  
  8904. ////////////////////////////////////////////////////////////////////////////////
  8905. //
  8906. // LynxFWIMUpdateDCLTimeStamp
  8907. //
  8908. //   This proc updates a DCL time stamp.  It reads the time stamp out of a PCL
  8909. // and writes it into the timeStamp field of the DCL.
  8910. //
  8911.  
  8912. static OSStatus        LynxFWIMUpdateDCLTimeStamp(
  8913.     DCLCommandPtr                pDCLCommand)
  8914. {
  8915.     DCLTimeStampPtr                pDCLTimeStamp;
  8916.     UInt32                        *pTimeStamp;
  8917.     OSStatus                    status = noErr;
  8918.  
  8919.     // Recast DCL command.
  8920.     pDCLTimeStamp = (DCLTimeStampPtr) pDCLCommand;
  8921.  
  8922.     // Copy time stamp from PCL.
  8923.     // Add one cycle since we're running ahead.
  8924.     //zzz have to be able to compute run ahead.  It can vary depending upon packet size.
  8925.     pTimeStamp = (UInt32 *) pDCLTimeStamp->compilerData;
  8926.     pDCLTimeStamp->timeStamp = EndianSwap32Bit (*pTimeStamp) + (1 << 12);
  8927.  
  8928.     return (status);
  8929. }
  8930.  
  8931.  
  8932. ////////////////////////////////////////////////////////////////////////////////
  8933. //
  8934. // LynxFWIMDCLCompilerModifyNotification
  8935. //
  8936. //   This proc handles modification notifications for the DCL to PCL compiler.
  8937. //zzz break this routine up
  8938. //
  8939.  
  8940. static OSStatus        LynxFWIMDCLCompilerModifyNotification(
  8941.     DCLProgramID                dclProgramID,
  8942.     DCLCommandPtr                *dclCommandList,
  8943.     UInt32                        numDCLCommands)
  8944. {
  8945.     DCLCommandPtr                pDCLCommand;
  8946.     DCLJumpPtr                    pDCLJump;
  8947.     DCLLabelPtr                    pDCLLabel;
  8948.     LynxPCLPtr                    pJumpPCL,
  8949.                                 pLabelPCL;
  8950.  
  8951.     DCLTransferPacketPtr        pDCLTransferPacket;
  8952.     LynxPCLPtr                    pTransferPacketPCL;
  8953.     UInt32                        pclControl;
  8954.     UInt32                        dclCommandNum;
  8955.     UInt32                        branchTargetPhys;
  8956.  
  8957.     OSStatus                    status = noErr;
  8958.  
  8959.     for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
  8960.     {
  8961.         // Get DCL command to update.
  8962.         pDCLCommand = *dclCommandList++;
  8963.  
  8964.         // Update command.
  8965.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  8966.         {
  8967.             case kDCLJumpOp :
  8968.  
  8969.                 // Recast.
  8970.                 pDCLJump = (DCLJumpPtr) pDCLCommand;
  8971.  
  8972.                 // Get label we're jumping to.
  8973.                 pDCLLabel = pDCLJump->pJumpDCLLabel;
  8974.  
  8975.                 // Get PCLs for jump and label DCLs.
  8976.                 pJumpPCL = LynxFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLJump);
  8977.                 pLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel);
  8978.  
  8979.                 if (pLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
  8980.                     branchTargetPhys = kLynxCPLINVALID;
  8981.                 else
  8982.                     branchTargetPhys = pLabelPCL->refCon;
  8983.                     
  8984.                 // Update jump PCL.
  8985.                 pJumpPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) branchTargetPhys);
  8986.  
  8987. #ifdef LynxVMDebug
  8988.                 if (((Ptr) (pLabelPCL)) !=
  8989.                     ((Ptr) (branchTargetPhys)))
  8990.                 {
  8991.                     sprintf (debugStr, "Updated jump   logical %08lx != physical %08lx",
  8992.                              (long) pLabelPCL,
  8993.                              (long) branchTargetPhys);
  8994.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  8995.                 }
  8996. #endif
  8997.                 break;
  8998.  
  8999.             case kDCLSendPacketWithHeaderStartOp :
  9000.                 //zzz support other transfer packet commands.
  9001.  
  9002.                 FWDebugStr ((ConstStr255Param) "/pOops, tried to update buffer, don't know how!");
  9003.  
  9004. // What would we do?
  9005. // We can't do what's done below - that fills in new PCL buffer addresses.  They aren't yet known.
  9006. // What we want is a PrepareMemoryForIO that covers all buffers in the new scheme.  I notice that
  9007. // we don't actually modify the base DCLs - I think we will have to do that.  So make one pass to
  9008. // modify the base DCLs.  Then call the general-purpose memory preparation routine, and let it
  9009. // create an all-new ioPrep (keep the old one).  Once that's done, we can re-scan the list of
  9010. // changes and make updates knowing the new physical addresses.  Finally, once the updates are
  9011. // all in place, it's impossible for any stale DMA to take place, so we can CheckpointIO on
  9012. // the old ioPrep struct and free its resources.  [Technically we should wait one packet to make
  9013. // sure that whatever Lynx's current DMA engine is doing is up to date.  Probably a good-enough
  9014. // way to do this is to postpone the CheckpointIO until before the NEXT round of updates, though
  9015. // that is somewhat wasteful if it ties down old buffers that aren't in use anymore...]
  9016. //
  9017. // We should find a safe way to make multiple updates to a PCL.  The user is in trouble anyway
  9018. // if we're changing a PCL while it runs, because they'll get the wrong data, but we want to
  9019. // make sure we don't send an illegally large packet (bad for 1394 bus) or overflow our receiver
  9020. // (could be bad for Lynx).  Perhaps we should copy command[0], set it to NOP+last, update the
  9021. // others, then update command[0].  That's safe unless we are inside the PCL but past command[0].
  9022. // After we set command[0] to NOP, we can check the DMA current cmd and make sure it is elsewhere.
  9023. //
  9024. // I don't suppose the user is required to use jump-updates to deactivate part of the program
  9025. // before updating that part?  That would be 100% safe if we know the jump-update worked on time.
  9026. //
  9027. // For safety we should probably pre-allocate a physAddr table and a rangeTable for two ioPrep
  9028. // structs, then we don't have to do any allocs here.  (though PrepareMemForIO might anyway).
  9029. // We know that the total number of buffers can't change, so rangeTable is OK.  When we prepare
  9030. // the physAddr table we should work out both the true size and the worst-case size.  Use the
  9031. // worst-case for alloc, use the true for PrepareMemoryForIO
  9032.  
  9033.                 // Recast.
  9034.                 pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  9035.  
  9036.                 // Get PCL.
  9037.                 pTransferPacketPCL =
  9038.                     LynxFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLTransferPacket);
  9039.  
  9040.                 // Update buffer size of transfer PCL.
  9041.                 pclControl = EndianSwap32Bit (pTransferPacketPCL->buffer[0].control);
  9042.                 pclControl = (pclControl & ~kLynxDMA_TransferCount) |
  9043.                              ((pDCLTransferPacket->size) << kLynxDMA_TransferCountPhase);
  9044.                 pTransferPacketPCL->buffer[0].control = EndianSwap32Bit (pclControl);
  9045.  
  9046.                 // Update buffer address of transfer PCL.
  9047.                 // WARNING WARNING this won't work with VM on - this is a logical address
  9048.                 pTransferPacketPCL->buffer[0].address =
  9049.                     (UInt32 *) EndianSwap32Bit ((UInt32) pDCLTransferPacket->buffer);
  9050.  
  9051.                 break;
  9052.  
  9053.             default :
  9054.  
  9055.                 break;
  9056.         }
  9057.     }
  9058.  
  9059.     return (status);
  9060. }
  9061.  
  9062.  
  9063. ////////////////////////////////////////////////////////////////////////////////
  9064. //
  9065. // LynxFWIMAllocatePCLBuildState
  9066. //
  9067. //   This proc allocates a PCL build state record.
  9068. //zzz we really don't need this.  should be allocated by other methods (stack?)
  9069. //
  9070.  
  9071. static OSStatus    LynxFWIMAllocatePCLBuildState(
  9072.     LynxFWIMDataPtr                pLynxFWIMData,
  9073.     LynxPCLBuildStatePtr        *ppLynxPCLBuildState)
  9074. {
  9075.     LynxPCLBuildStatePtr        pLynxPCLBuildState;
  9076.     OSStatus                    status = noErr;
  9077.     
  9078.     // Allocate memory for record.
  9079.     pLynxPCLBuildState =
  9080.         (LynxPCLBuildStatePtr) PoolAllocateResident (sizeof (LynxPCLBuildState), true);
  9081.     if (pLynxPCLBuildState == nil)
  9082.         status = memFullErr;
  9083.  
  9084.     // Return results.
  9085.     if (status == noErr)
  9086.         *ppLynxPCLBuildState = pLynxPCLBuildState;
  9087.     else
  9088.         *ppLynxPCLBuildState = nil;
  9089.  
  9090.     return (status);
  9091. }
  9092.  
  9093.  
  9094. ////////////////////////////////////////////////////////////////////////////////
  9095. //
  9096. // LynxFWIMAllocatePCL
  9097. //
  9098. //   This proc allocates a PCL.
  9099. //
  9100.  
  9101. static OSStatus    LynxFWIMAllocatePCL(
  9102.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  9103.     LynxPCLPtr                    *ppPCL)
  9104. {
  9105.     LynxPCLPoolDataPtr            pLynxPCLPoolData;
  9106.     LynxPCLPtr                    pPCL,
  9107.                                 pclPool;
  9108.     UInt32                        pclPoolPhys;
  9109.     UInt32                        nextFreePCL;
  9110.     IOPreparationTable            *ioPrep;
  9111.     UInt32                        pageSize, allocSize;
  9112.     Ptr                            p;
  9113.     OSStatus                    status = noErr;
  9114.     
  9115.     // Get PCL pool data record.
  9116.     pLynxPCLPoolData = pLynxPCLBuildState->pLynxPCLPoolDataList;
  9117.     
  9118.     // Get PCL pool and next free PCL index.
  9119.     if (pLynxPCLPoolData != nil)
  9120.     {
  9121.         pclPool = pLynxPCLPoolData->alignedPCLPoolBase;
  9122.         pclPoolPhys = pLynxPCLPoolData->alignedPCLPoolBasePhys;
  9123.         nextFreePCL = pLynxPCLPoolData->nextFreePCL;
  9124.     }
  9125.     else
  9126.     {
  9127.         pclPool = nil;
  9128.     }
  9129.     
  9130.     // Allocate new pool if current pool is exhausted.
  9131.     // This pool needs to be aligned to the PCL size for the PCL compilation logic
  9132.     // to work properly.  Pool size can exceed one phys page as long as we have an
  9133.     // allocator which gives us contiguous pages.
  9134.     
  9135.     if ((pclPool == nil) || (nextFreePCL >= kPCLPoolSize))
  9136.     {
  9137.         pageSize = GetLogicalPageSize ();
  9138.         allocSize = sizeof (LynxPCLPoolData) + sizeof (LynxPCL);
  9139.         
  9140.         // Not knowing if MemAllocPhysCont returns page-aligned data, we need to
  9141.         // add one page to align and one more to flush out the end of the struct.
  9142.         // (Could be done more tightly.)
  9143.         
  9144.         allocSize = (allocSize / pageSize) + 3;        // sloppy
  9145.         
  9146.         p = MemAllocatePhysicallyContiguous (allocSize * pageSize, true);
  9147.         if (p != nil)
  9148.         {
  9149.             // Page align
  9150.             pLynxPCLPoolData = (LynxPCLPoolDataPtr)
  9151.                 (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1));
  9152.             
  9153.             // Store original
  9154.             pLynxPCLPoolData->poolAllocatedAddress = (LogicalAddress) p;
  9155.             
  9156.             ioPrep = &pLynxPCLPoolData->ioPrep;
  9157.             
  9158.             // Prepare for IO and get physical address
  9159.             ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  9160.             ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  9161.             ioPrep->granularity = 0;                                // do it all now
  9162.             ioPrep->firstPrepared = 0;
  9163.             ioPrep->mappingEntryCount = allocSize - 1;                // # of pages we will use
  9164.             ioPrep->logicalMapping = 0;
  9165.             ioPrep->physicalMapping = pLynxPCLPoolData->physAddrs;    // return list of phys addrs
  9166.             ioPrep->rangeInfo.range.base = (void *) pLynxPCLPoolData;
  9167.             ioPrep->rangeInfo.range.length = (allocSize - 1) * pageSize;
  9168.             
  9169.             // The CheckpointIO is in LynxFWIMDeallocatePCLPools
  9170.             status = PrepareMemoryForIO (ioPrep);
  9171.             if (status != noErr)
  9172.             {
  9173.                 sprintf (debugStr, "PCL Pool PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  9174.                          (long) status,
  9175.                          (long) ioPrep->rangeInfo.range.base,
  9176.                          (long) pLynxPCLPoolData->physAddrs[0],
  9177.                          (long) ioPrep->rangeInfo.range.length);
  9178.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  9179.             }
  9180.  
  9181.             pLynxPCLPoolData->pNextLynxPCLPoolData =
  9182.                 pLynxPCLBuildState->pLynxPCLPoolDataList;
  9183.             pLynxPCLBuildState->pLynxPCLPoolDataList = pLynxPCLPoolData;
  9184.             // Never use pclPoolDummy.  (This is the only place)  It does not index
  9185.             // the true aligned PCLs.  Use alignedPCLPoolBase as an array instead.
  9186.             pLynxPCLPoolData->alignedPCLPoolBase = (LynxPCLPtr)
  9187.                 (((UInt32) &(pLynxPCLPoolData->pclPoolDummy[1])) & kPCLAlignmentMask);
  9188.  
  9189.             pLynxPCLPoolData->alignedPCLPoolBasePhys =
  9190.                 (UInt32) pLynxPCLPoolData->physAddrs[0] +
  9191.                 ((UInt32) pLynxPCLPoolData->alignedPCLPoolBase - (UInt32) pLynxPCLPoolData);
  9192.             
  9193.             // In the first allocated pool, we keep space for the isoch packet
  9194.             // header (for transmit).  Work out its location and store it away.
  9195.             // Note we only really need to do this the first time.  Note also
  9196.             // that whoever is going to use this better make a copy before the
  9197.             // second time we come here.
  9198.             
  9199.             pLynxPCLPoolData->isochPacketHeaderPhys = (PhysicalAddress)
  9200.                 ((UInt32) pLynxPCLPoolData->physAddrs[0] +
  9201.                  ((UInt32) &(pLynxPCLPoolData->isochPacketHeader) - (UInt32) pLynxPCLPoolData));
  9202.                         
  9203. #ifdef LynxVMDebug
  9204.             if (((Ptr) (&(pLynxPCLPoolData->isochPacketHeader))) !=
  9205.                 ((Ptr) (pLynxPCLPoolData->isochPacketHeaderPhys)))
  9206.             {
  9207.                 sprintf (debugStr, "Isoch header store  logical %08lx != physical %08lx",
  9208.                          (long) (&(pLynxPCLPoolData->isochPacketHeader)),
  9209.                          (long) pLynxPCLPoolData->isochPacketHeaderPhys);
  9210.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  9211.             }
  9212. #endif
  9213.             nextFreePCL = 0;
  9214.             pclPool = pLynxPCLPoolData->alignedPCLPoolBase;
  9215.             pclPoolPhys = pLynxPCLPoolData->alignedPCLPoolBasePhys;
  9216.         }
  9217.         else
  9218.         {
  9219.             status = memFullErr;
  9220.         }
  9221.     }
  9222.     
  9223.     // Allocate PCL from pool.
  9224.     if (status == noErr)
  9225.     {
  9226.         pPCL = &(pclPool[nextFreePCL++]);
  9227.         pPCL->refCon = pclPoolPhys + (((UInt32) pPCL) - ((UInt32) pclPool));
  9228.         pLynxPCLPoolData->nextFreePCL = nextFreePCL;
  9229. #ifdef LynxVMDebug
  9230.         if (((Ptr) (pPCL)) != ((Ptr) (pPCL->refCon)))
  9231.         {
  9232.             sprintf (debugStr, "PCL alloc logical %08lx != physical %08lx",
  9233.                      (long) pPCL,
  9234.                      (long) pPCL->refCon);
  9235.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  9236.         }
  9237. #endif
  9238.     }
  9239.  
  9240.     // Initialize the PCL.
  9241.     if (status == noErr)
  9242.     {
  9243.         pPCL->nextPCL = (UInt32 *) EndianSwap32Bit (kLynxCPLINVALID);
  9244.         pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  9245.         pPCL->status = EndianSwapImm32Bit (0);
  9246.         pPCL->remaining = EndianSwapImm32Bit (0);
  9247.         pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
  9248.     }
  9249.  
  9250.     // Return results.
  9251.     if (status == noErr)
  9252.         *ppPCL = pPCL;
  9253.     else
  9254.         *ppPCL = nil;
  9255.  
  9256.     return (status);
  9257. }
  9258.  
  9259.  
  9260. ////////////////////////////////////////////////////////////////////////////////
  9261. //
  9262. // LynxFWIMDeallocatePCLPools
  9263. //
  9264. //   This proc deallocates the given list of PCL pools.
  9265. //
  9266.  
  9267. static void LynxFWIMDeallocatePCLPools(
  9268.     LynxPCLPoolDataPtr            pLynxPCLPoolDataList)
  9269. {
  9270.     LynxPCLPoolDataPtr            pLynxPCLPoolData,
  9271.                                 pNextLynxPCLPoolData;
  9272.     OSStatus                    status = noErr;
  9273.  
  9274.     // Deallocate each pool in list.
  9275.     pLynxPCLPoolData = pLynxPCLPoolDataList;
  9276.     while (pLynxPCLPoolData != nil)
  9277.     {
  9278.         pNextLynxPCLPoolData = pLynxPCLPoolData->pNextLynxPCLPoolData;
  9279.         status = CheckpointIO (pLynxPCLPoolData->ioPrep.preparationID, kNilOptions);
  9280.         if (status != noErr)
  9281.         {
  9282.             sprintf (debugStr, "PCL Pool CheckpointIO status %ld    ID was %08lx",
  9283.                      (long) status,
  9284.                      (long) pNextLynxPCLPoolData->ioPrep.preparationID);
  9285.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  9286.         }
  9287.         if (MemDeallocatePhysicallyContiguous (pLynxPCLPoolData->poolAllocatedAddress) != noErr)
  9288.             FWDebugStr ((ConstStr255Param) "\p Dealloc error!!");
  9289.         pLynxPCLPoolData = pNextLynxPCLPoolData;
  9290.     }
  9291. }
  9292.  
  9293.  
  9294. ////////////////////////////////////////////////////////////////////////////////
  9295. //
  9296. // LynxFWIMRunDCLProgram
  9297. //
  9298. //   This proc uses the given packet to run through the DCL program.
  9299. //   This is obsolete, but shows how one could manually process DCLs.
  9300. //
  9301.  
  9302. static void    LynxFWIMRunDCLProgram(
  9303.     LynxIsochPortDataPtr        pLynxIsochPortData,
  9304.     Ptr                            packetBuffer,
  9305.     UInt32                        packetSize,
  9306.     DCLCommandPtr                *ppDCLCommand)
  9307. {
  9308.     DCLCommandPtr                pDCLCommand;
  9309.     DCLCallProcPtr                pDCLCallProc;
  9310.     DCLJumpPtr                    pDCLJump;
  9311.     UInt32                        packetSizeLeft;
  9312.     Boolean                        waitForPacket;
  9313.  
  9314.     // Process packet data.
  9315.     pDCLCommand = *ppDCLCommand;
  9316.     packetSizeLeft = packetSize;
  9317.     waitForPacket = false;
  9318.     while ((pDCLCommand != nil) && (!waitForPacket))
  9319.     {
  9320.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  9321.         {
  9322.             case kDCLReceivePacketStartOp :
  9323.                 if (packetSize > 0)
  9324.                 {
  9325.                     LynxFWIMDCLReceivePacketStart
  9326.                         (&packetBuffer, &packetSize, &pDCLCommand, &waitForPacket);
  9327.                 }
  9328.                 else
  9329.                 {
  9330.                     waitForPacket = true;
  9331.                 }
  9332.                 break;
  9333.  
  9334.             case kDCLReceiveBufferOp :
  9335.                 packetBuffer += sizeof (UInt32); // Skip header//zzz not quite right.
  9336.                 LynxFWIMDCLReceiveBuffer
  9337.                     (&packetBuffer, &packetSize, &pDCLCommand, &waitForPacket);
  9338.                 break;
  9339.                 
  9340.             case kDCLCallProcOp :
  9341.                 pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  9342.                 FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
  9343.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  9344.                 break;
  9345.                 
  9346.             case kDCLJumpOp :
  9347.                 pDCLJump = (DCLJumpPtr) pDCLCommand;
  9348.                 pDCLCommand = (DCLCommandPtr) pDCLJump->pJumpDCLLabel;
  9349.                 break;
  9350.  
  9351.             default :
  9352.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  9353.                 break;
  9354.         }
  9355.     }
  9356.     
  9357.     // Update current DCL command.
  9358.     *ppDCLCommand = pDCLCommand;
  9359. }
  9360.  
  9361.  
  9362. ////////////////////////////////////////////////////////////////////////////////
  9363. //
  9364. // LynxFWIMDCLReceivePacketStart
  9365. //
  9366. //   This proc processes a DCL receive packet command.
  9367. //   This is obsolete, but shows how one could manually process DCLs.
  9368. //
  9369.  
  9370. static void    LynxFWIMDCLReceivePacketStart(
  9371.     Ptr                            *pPacketBuffer,
  9372.     UInt32                        *pPacketSize,
  9373.     DCLCommandPtr                *ppDCLCommand,
  9374.     Boolean                        *pWaitForPacket)
  9375. {
  9376.     DCLTransferPacketPtr        pDCLTransferPacket;
  9377.     UInt32                        packetSize;
  9378.     UInt32                        dclPacketSize;
  9379.     UInt32                        transferSize;
  9380.  
  9381.     // Recast DCL command.
  9382.     pDCLTransferPacket = (DCLTransferPacketPtr) *ppDCLCommand;
  9383.     
  9384.     // Compute transfer size.
  9385.     dclPacketSize = pDCLTransferPacket->size;
  9386.     packetSize = *pPacketSize + sizeof (UInt32);//zzz include header
  9387.     if (dclPacketSize > packetSize)
  9388.         transferSize = packetSize;
  9389.     else
  9390.         transferSize = dclPacketSize;
  9391.  
  9392.     // Transfer the packet data.
  9393.     if (transferSize > 0)
  9394.         BlockCopy (*pPacketBuffer, pDCLTransferPacket->buffer, transferSize);
  9395.     
  9396.     // We're done with DCL and packet.
  9397.     *ppDCLCommand = pDCLTransferPacket->pNextDCLCommand;
  9398.     *pPacketSize = 0;
  9399.     *pWaitForPacket = false;
  9400. }
  9401.  
  9402.  
  9403. ////////////////////////////////////////////////////////////////////////////////
  9404. //
  9405. // LynxFWIMDCLReceiveBuffer
  9406. //
  9407. //   This proc processes a DCL receive buffer command.
  9408. //   This is obsolete, but shows how one could manually process DCLs.
  9409. //
  9410.  
  9411. static void    LynxFWIMDCLReceiveBuffer(
  9412.     Ptr                            *pPacketBuffer,
  9413.     UInt32                        *pPacketSize,
  9414.     DCLCommandPtr                *ppDCLCommand,
  9415.     Boolean                        *pWaitForPacket)
  9416. {
  9417.     DCLTransferBufferPtr        pDCLTransferBuffer;
  9418.     UInt32                        bufferSizeLeft;
  9419.     UInt32                        packetSize;
  9420.     UInt32                        transferSize;
  9421.  
  9422.     // Recast DCL command.
  9423.     pDCLTransferBuffer = (DCLTransferBufferPtr) *ppDCLCommand;
  9424.     
  9425.     // Compute transfer size.
  9426.     bufferSizeLeft = pDCLTransferBuffer->size - pDCLTransferBuffer->bufferOffset;
  9427.     packetSize = *pPacketSize;
  9428.     if (bufferSizeLeft > packetSize)
  9429.         transferSize = packetSize;
  9430.     else
  9431.         transferSize = bufferSizeLeft;
  9432.  
  9433.     // Transfer the packet data.
  9434.     if (transferSize > 0)
  9435.     {
  9436.         BlockCopy (*pPacketBuffer,
  9437.                    pDCLTransferBuffer->buffer + pDCLTransferBuffer->bufferOffset,
  9438.                    transferSize);
  9439.         
  9440.         *pPacketBuffer += transferSize;
  9441.         *pPacketSize -= transferSize;
  9442.         pDCLTransferBuffer->bufferOffset += transferSize;
  9443.     }
  9444.     
  9445.     // Check if we're done with this DCL or need another packet.
  9446.     if (pDCLTransferBuffer->bufferOffset == pDCLTransferBuffer->size)
  9447.     {
  9448.         *ppDCLCommand = pDCLTransferBuffer->pNextDCLCommand;
  9449.         *pWaitForPacket = false;
  9450.     }
  9451.     else
  9452.     {
  9453.         *pWaitForPacket = true;
  9454.     }
  9455. }
  9456.  
  9457.  
  9458. ////////////////////////////////////////////////////////////////////////////////
  9459. //
  9460. // LynxFWIMAllocateIsochPort
  9461. //
  9462. //   This routine will allocate an isochronous channel.
  9463. //zzz must make sure that port is not already in use.
  9464. //zzz should do more error checking.
  9465. //zzz we may need to keep a list of isoch port data records.
  9466. //
  9467.  
  9468. static OSStatus LynxFWIMAllocateIsochPort(
  9469.     FWIMAllocateIsochPortParamsPtr
  9470.                                 pFWIMAllocateIsochPortParams,
  9471.     UInt32                        *pCommandAcceptance)
  9472. {
  9473.     FWIMCommandParamsPtr        pFWIMCommandParams;
  9474.     LynxFWIMDataPtr                pLynxFWIMData;
  9475.     LynxIsochPortDataPtr        pLynxIsochPortData = nil;
  9476.     LynxRegistersPtr            pLynxRegs;
  9477.     SInt32                        dmaChannelNum;
  9478.     UInt32                        isochChannelNum;
  9479.     Boolean                        talking;
  9480.     OSStatus                    status = noErr;
  9481.  
  9482. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMAllocateIsochPort");
  9483.  
  9484.     // Get our internal data.
  9485.     pFWIMCommandParams = &(pFWIMAllocateIsochPortParams->fwimCommandParams);
  9486.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  9487.  
  9488.     // Set pending command.
  9489.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAllocateIsochPortParams;
  9490.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  9491.  
  9492.     // Get base address of Lynx registers.
  9493.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  9494.     
  9495.     // Are we talking?
  9496.     talking = pFWIMAllocateIsochPortParams->talking;
  9497.  
  9498.     // find a free dma channel.
  9499.     dmaChannelNum = LynxAllocateDMAChannel( pLynxFWIMData );
  9500.  
  9501.     if (talking)
  9502.         pLynxFWIMData->DMAInfo[dmaChannelNum].channelType = kIsochXmit;
  9503.     else
  9504.         pLynxFWIMData->DMAInfo[dmaChannelNum].channelType = kIsochRcv;
  9505.  
  9506.     if( pLynxFWIMData->phyNotPowered )
  9507.         status = accessErr;     // !!! Proper error?
  9508.     
  9509.     // if dma channel is not in use
  9510.     if ( !status && dmaChannelNum >= 0 && pLynxFWIMData->lynxIsochPortDataList[dmaChannelNum] == nil)
  9511.     {
  9512.  
  9513.         // Create an isoch port data record.
  9514.         pLynxIsochPortData =
  9515.             (LynxIsochPortDataPtr) PoolAllocateResident (sizeof (LynxIsochPortData), true);
  9516.         if (pLynxIsochPortData != nil)
  9517.         {
  9518.             pLynxFWIMData->lynxIsochPortDataList[dmaChannelNum] = pLynxIsochPortData;
  9519.             pLynxIsochPortData->originalDCLProgramID =
  9520.                 pFWIMAllocateIsochPortParams->dclProgramID;
  9521.             pLynxIsochPortData->translatedDCLProgramID = kInvalidDCLProgramID;
  9522.             pLynxIsochPortData->channelNum = pFWIMAllocateIsochPortParams->channelNum;
  9523.             pLynxIsochPortData->speed = pFWIMAllocateIsochPortParams->speed;
  9524.             pLynxIsochPortData->talking = talking;
  9525.             pLynxIsochPortData->dmaChannel = dmaChannelNum;
  9526.             // Enable appropriate Interrupts
  9527.             LynxFWIMInterruptSetup( pLynxFWIMData );
  9528.         }
  9529.         else
  9530.         {
  9531.             status = memFullErr;
  9532.         }
  9533.         
  9534.         // Compile a PCL program from DCL program.
  9535.         if (status == noErr)
  9536.         {
  9537.             // Check if DCL program must be translated.
  9538.             if (LynxFWIMIsCompilableDCLProgram (pLynxIsochPortData->originalDCLProgramID))
  9539.             {
  9540.                 pLynxIsochPortData->dclProgramID = pLynxIsochPortData->originalDCLProgramID;
  9541.                 pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram = pLynxIsochPortData->dclProgramID;
  9542.             }
  9543.             else
  9544.             {
  9545.                 //zzz need to be able to deallocate this.
  9546.                 status = FWTranslateDCLProgram (pLynxIsochPortData->originalDCLProgramID,
  9547.                                                 &(pLynxIsochPortData->translatedDCLProgramID));
  9548.                 if (status == noErr)
  9549.                 {
  9550.                     pLynxIsochPortData->dclProgramID =
  9551.                         pLynxIsochPortData->translatedDCLProgramID;
  9552.                     pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram = pLynxIsochPortData->dclProgramID;
  9553.                 }
  9554.             }
  9555.             
  9556.             // Compile the DCL program.
  9557.             if (status == noErr)
  9558.             {
  9559.                 status = LynxFWIMCompileDCLProgram
  9560.                             (pLynxFWIMData,
  9561.                              pLynxIsochPortData->dclProgramID,
  9562.                              dmaChannelNum,
  9563.                              pLynxIsochPortData->channelNum,
  9564.                              pLynxIsochPortData->speed);
  9565.             }
  9566.     
  9567.             // Set start, stop, and release procedures for DCL program.
  9568.             if (status == noErr)
  9569.             {
  9570.                 if (talking)
  9571.                 {
  9572.                     FWSetDCLProgramStartProc (pLynxIsochPortData->dclProgramID,
  9573.                                               LynxFWIMStartTalkingDCLProgram);
  9574.                     FWSetDCLProgramStopProc (pLynxIsochPortData->dclProgramID,
  9575.                                              LynxFWIMStopTalkingDCLProgram);
  9576.                     FWSetDCLProgramReleaseProc (pLynxIsochPortData->dclProgramID,
  9577.                                                 LynxFWIMReleaseDCLProgram);
  9578.                 }
  9579.                 else
  9580.                 {
  9581.                     FWSetDCLProgramStartProc (pLynxIsochPortData->dclProgramID,
  9582.                                               LynxFWIMStartListeningDCLProgram);
  9583.                     FWSetDCLProgramStopProc (pLynxIsochPortData->dclProgramID,
  9584.                                              LynxFWIMStopListeningDCLProgram);
  9585.                     FWSetDCLProgramReleaseProc (pLynxIsochPortData->dclProgramID,
  9586.                                                 LynxFWIMReleaseDCLProgram);
  9587.                 }
  9588.             }
  9589.         }
  9590.     
  9591.         // Set up appropriate DMA channel.
  9592.         if (status == noErr)
  9593.         {
  9594.             // Quiet the DMA channel.
  9595.             pLynxRegs->dmaChannel[dmaChannelNum].control = EndianSwapImm32Bit (0);
  9596.             SynchronizeIO ();
  9597.     
  9598.             // Switch to isochronous transmit mode if we're talking.
  9599.             if (talking)
  9600.             {
  9601.                 IncrementAtomic( &pLynxFWIMData->isochTransmitMode);
  9602.                 LynxFWIMSetupFIFOs (pLynxFWIMData);
  9603.             }
  9604.     
  9605.             // Set up comparators to receive on this port's channel.
  9606.             if (!talking)
  9607.             {
  9608.                 isochChannelNum = pLynxIsochPortData->channelNum;
  9609.                 status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  9610.                             (UInt32 *) &pLynxRegs->dmaComparator[dmaChannelNum].value0,
  9611.                             (UInt32)EndianSwapImm32Bit (isochChannelNum << kLynxCMP0_FIELD2_MASKPhase));
  9612.  
  9613.                 if( !status ) {
  9614.                     status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  9615.                                 (UInt32 *) &pLynxRegs->dmaComparator[dmaChannelNum].mask0,
  9616.                                 (UInt32)EndianSwapImm32Bit ((kLynxIsotCodeNormal << kLynxCMP0_FIELD3_MASKPhase) |
  9617.                                             (kLynxMatchIsochChannel << kLynxCMP0_FIELD2_MASKPhase)));
  9618.                 }
  9619.                 SynchronizeIO ();
  9620.             }
  9621.     
  9622.             // Set our data for port.
  9623.             pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData =
  9624.                 (UInt32) pLynxIsochPortData;
  9625.         }
  9626.     
  9627.         // Clean up on error.
  9628.         if (status != noErr)
  9629.         {
  9630.             if (pLynxIsochPortData != nil)
  9631.                 _LynxFWIMReleaseIsochPort (pLynxFWIMData, pLynxIsochPortData);
  9632.         }
  9633.     }
  9634.     else
  9635.     {
  9636.         // dma channel is in use
  9637.         status = paramErr;        // better error?
  9638.     }
  9639.  
  9640.     // Complete FWIM command.
  9641.     pLynxFWIMData->pPendingFWIMCommand = nil;
  9642.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  9643.  
  9644.     // Return command acceptance.
  9645.     //zzz what if we call FWIMCommandIsComplete before returning this???
  9646.     //zzz well, it still works, but will it always?
  9647.     //zzz actually, when we switch to the dispatch table, each routine can return
  9648.     //zzz the appropriate acceptance, so don't worry about it for now.
  9649.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  9650.  
  9651.     return (status);
  9652. }
  9653.  
  9654.  
  9655. ////////////////////////////////////////////////////////////////////////////////
  9656. //
  9657. // LynxFWIMReleaseIsochPort
  9658. //
  9659. //   This routine will release resources allocated for the given isochronous
  9660. // channel.
  9661. //
  9662.  
  9663. static OSStatus LynxFWIMReleaseIsochPort(
  9664.     FWIMReleaseIsochPortParamsPtr
  9665.                                 pFWIMReleaseIsochPortParams,
  9666.     UInt32                        *pCommandAcceptance)
  9667. {
  9668.     FWIMCommandParamsPtr        pFWIMCommandParams;
  9669.     LynxFWIMDataPtr                pLynxFWIMData;
  9670.     LynxIsochPortDataPtr        pLynxIsochPortData;
  9671.     OSStatus                    status = noErr;
  9672.  
  9673. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMReleaseIsochPort");
  9674.  
  9675.     // Get our internal data.
  9676.     pFWIMCommandParams = &(pFWIMReleaseIsochPortParams->fwimCommandParams);
  9677.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  9678.  
  9679.     // Set pending command.
  9680.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMReleaseIsochPortParams;
  9681.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  9682.  
  9683.     // Get isoch port data.
  9684.     pLynxIsochPortData = (LynxIsochPortDataPtr)
  9685.         pFWIMReleaseIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
  9686.  
  9687.     // Release resources for isoch port.
  9688.     if (pLynxIsochPortData != nil)
  9689.         status = _LynxFWIMReleaseIsochPort (pLynxFWIMData, pLynxIsochPortData);
  9690.  
  9691.     // Complete FWIM command.
  9692.     pLynxFWIMData->pPendingFWIMCommand = nil;
  9693.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  9694.  
  9695.     // Return command acceptance.
  9696.     //zzz what if we call FWIMCommandIsComplete before returning this???
  9697.     //zzz well, it still works, but will it always?
  9698.     //zzz actually, when we switch to the dispatch table, each routine can return
  9699.     //zzz the appropriate acceptance, so don't worry about it for now.
  9700.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  9701.  
  9702.     return (status);
  9703. }
  9704.  
  9705.  
  9706. ////////////////////////////////////////////////////////////////////////////////
  9707. //
  9708. // _LynxFWIMReleaseIsochPort
  9709. //
  9710. //   This routine will release resources allocated for the given isochronous
  9711. // channel.
  9712. //
  9713.  
  9714. static OSStatus _LynxFWIMReleaseIsochPort(
  9715.     LynxFWIMDataPtr                pLynxFWIMData,
  9716.     LynxIsochPortDataPtr        pLynxIsochPortData)
  9717. {
  9718.     LynxDCLCompilerEngineDataPtr
  9719.                                 pLynxDCLCompilerEngineData = nil;
  9720.     OSStatus                    status = noErr;
  9721.  
  9722.     // Clear isoch port data from fwim list
  9723.     if (pLynxFWIMData->lynxIsochPortDataList[pLynxIsochPortData->dmaChannel] == pLynxIsochPortData)
  9724.         pLynxFWIMData->lynxIsochPortDataList[pLynxIsochPortData->dmaChannel] = nil;
  9725.         
  9726.     // Give back the DMA channel and setup the interrupts correctly again
  9727.     LynxDeAllocateDMAChannel( pLynxFWIMData, pLynxIsochPortData->dmaChannel );
  9728.  
  9729.     // If we're releasing a talking port, switch out of isoch transmit mode.
  9730.     if (pLynxIsochPortData->talking)
  9731.     {
  9732.         // Switch out of isochronous transmit mode.
  9733.         DecrementAtomic( &pLynxFWIMData->isochTransmitMode);
  9734.         LynxFWIMSetupFIFOs (pLynxFWIMData);
  9735.     }
  9736.     
  9737.     // Release DCL resources.
  9738.     if (pLynxIsochPortData->originalDCLProgramID != kInvalidDCLProgramID)
  9739.         status = FWReleaseDCLProgram (pLynxIsochPortData->originalDCLProgramID);
  9740.     
  9741.     // Deallocate isoch port data record.
  9742.     PoolDeallocate ((Ptr) pLynxIsochPortData);
  9743.     
  9744.     return (status);
  9745. }
  9746.  
  9747.  
  9748. ////////////////////////////////////////////////////////////////////////////////
  9749. //
  9750. // LynxFWIMStartIsochPort
  9751. //
  9752. //   Start up the given isochronous port on the given sync event using the
  9753. // given buffer.
  9754. //
  9755.  
  9756. static OSStatus LynxFWIMStartIsochPort(
  9757.     FWIMIsochPortControlParamsPtr
  9758.                                 pFWIMIsochPortControlParams,
  9759.     UInt32                        *pCommandAcceptance)
  9760. {
  9761.     FWIMCommandParamsPtr        pFWIMCommandParams;
  9762.     LynxFWIMDataPtr                pLynxFWIMData;
  9763.     LynxIsochPortDataPtr        pLynxIsochPortData;
  9764.     OSStatus                    status = noErr;
  9765.  
  9766. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMStartIsochPort");
  9767.  
  9768.     // Get our internal data.
  9769.     pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
  9770.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  9771.  
  9772.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  9773.  
  9774.     // Set pending command.
  9775.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
  9776.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  9777.  
  9778.     // Get isoch port data.
  9779.     pLynxIsochPortData = (LynxIsochPortDataPtr)
  9780.         pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
  9781.  
  9782.     if( pLynxFWIMData->phyNotPowered )
  9783.         status = accessErr;     // !!! Proper error?
  9784.     
  9785.     // Start DCL program.
  9786.     if (status == noErr)
  9787.         status = FWStartDCLProgram (pLynxIsochPortData->originalDCLProgramID);
  9788.  
  9789.     // Finish up command.
  9790.     pLynxFWIMData->pPendingFWIMCommand = nil;
  9791.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  9792.  
  9793.     // Return command acceptance.
  9794.     //zzz what if we call FWIMCommandIsComplete before returning this???
  9795.     //zzz well, it still works, but will it always?
  9796.     //zzz actually, when we switch to the dispatch table, each routine can return
  9797.     //zzz the appropriate acceptance, so don't worry about it for now.
  9798.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  9799.  
  9800.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  9801.  
  9802.     return (status);
  9803. }
  9804.  
  9805.  
  9806. ////////////////////////////////////////////////////////////////////////////////
  9807. //
  9808. // LynxFWIMStopIsochPort
  9809. //
  9810. //   Stop the given isochronous port on the given sync event.
  9811. //
  9812.  
  9813. static OSStatus LynxFWIMStopIsochPort(
  9814.     FWIMIsochPortControlParamsPtr
  9815.                                 pFWIMIsochPortControlParams,
  9816.     UInt32                        *pCommandAcceptance)
  9817. {
  9818.     FWIMCommandParamsPtr        pFWIMCommandParams;
  9819.     LynxFWIMDataPtr                pLynxFWIMData;
  9820.     LynxIsochPortDataPtr        pLynxIsochPortData;
  9821.     OSStatus                    status = noErr;
  9822.  
  9823. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMStopIsochPort");
  9824.  
  9825.     // Get our internal data.
  9826.     pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
  9827.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  9828.  
  9829.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  9830.  
  9831.     // Set pending command.
  9832.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
  9833.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  9834.  
  9835.     // Get isoch port data.
  9836.     pLynxIsochPortData = (LynxIsochPortDataPtr)
  9837.         pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
  9838.  
  9839.     // Stop DCL program.
  9840.     if (status == noErr)
  9841.         status = FWStopDCLProgram (pLynxIsochPortData->originalDCLProgramID);
  9842.  
  9843.     // Finish up command.
  9844.     pLynxFWIMData->pPendingFWIMCommand = nil;
  9845.     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  9846.  
  9847.     // Return command acceptance.
  9848.     //zzz what if we call FWIMCommandIsComplete before returning this???
  9849.     //zzz well, it still works, but will it always?
  9850.     //zzz actually, when we switch to the dispatch table, each routine can return
  9851.     //zzz the appropriate acceptance, so don't worry about it for now.
  9852.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  9853.  
  9854.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  9855.  
  9856.     return (status);
  9857. }
  9858.  
  9859.  
  9860. ////////////////////////////////////////////////////////////////////////////////
  9861. //
  9862. // LynxFWIMStartTalkingDCLProgram
  9863. //
  9864. //   This routine starts running the given DCL program.
  9865. //
  9866.  
  9867. static OSStatus LynxFWIMStartTalkingDCLProgram(
  9868.     DCLProgramID                dclProgramID)
  9869. {
  9870.     LynxDCLCompilerEngineDataPtr
  9871.                                 pLynxDCLCompilerEngineData;
  9872.     LynxFWIMDataPtr                pLynxFWIMData;
  9873.     LynxRegistersPtr            pLynxRegs;
  9874.     OSStatus                    status = noErr;
  9875.     UInt32                        dmaChannelNum;
  9876.  
  9877.     // Get our engine data and FWIM data.
  9878.     status = FWGetDCLProgramEngineData
  9879.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  9880.     if (status == noErr)
  9881.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  9882.  
  9883.     // Get base address of Lynx registers.
  9884.     if (status == noErr)
  9885.         pLynxRegs = pLynxFWIMData->pLynxRegisters;
  9886.  
  9887.     // Start the DMA engine.
  9888.     if (status == noErr)
  9889.     {
  9890.         // Figure out what DMA channel is used by this DCL
  9891.         dmaChannelNum = 0;
  9892.         while( dmaChannelNum < kNumDMAChannels ) {
  9893.             if( pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram == dclProgramID )
  9894.                 break;
  9895.             dmaChannelNum++;
  9896.         }
  9897.         
  9898.         SynchronizeIO();// • Damn Compiler Bug! If this isn't here the value of dmaChannelNum gets munged.
  9899.         if( dmaChannelNum < kNumDMAChannels ) {
  9900.             // We'll report statistics at the end of the transmit, if FireBug enabled.
  9901.             status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  9902.                     (UInt32 *) &pLynxRegs->fifoOverUnderErrorCounters,
  9903.                     (UInt32) EndianSwapImm32Bit (0) );
  9904.             
  9905.             if( !status ) {
  9906.                 // Load a physical address
  9907.                 pLynxRegs->dmaChannel[dmaChannelNum].curPCLAddr =
  9908.                     EndianSwap32Bit ((UInt32) pLynxDCLCompilerEngineData->pStartPCL->refCon);
  9909.                 SynchronizeIO ();
  9910.         
  9911.                 // Set CH ENA and Link bits to enable DMA.
  9912.                 pLynxRegs->dmaChannel[dmaChannelNum].control =
  9913.                     EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  9914.                 SynchronizeIO ();
  9915.                 
  9916.                 // In rare cases, we might not start transmitting.  Somehow the FIFO gets jammed,
  9917.                 // even though we flush it before and after iso transmit programs run.  I have
  9918.                 // only seen this in pre-revA parts, so maybe it's one of the errata items.
  9919.             }
  9920.         }
  9921.         else
  9922.             status = channelNotAvailableErr;    // Should never happen, I think.
  9923.     }
  9924.  
  9925.     return (status);
  9926. }
  9927.  
  9928.  
  9929. ////////////////////////////////////////////////////////////////////////////////
  9930. //
  9931. // LynxFWIMStartListeningDCLProgram
  9932. //
  9933. //   This routine starts running the given DCL program.
  9934. //
  9935.  
  9936. static OSStatus LynxFWIMStartListeningDCLProgram(
  9937.     DCLProgramID                dclProgramID)
  9938. {
  9939.     LynxDCLCompilerEngineDataPtr
  9940.                                 pLynxDCLCompilerEngineData;
  9941.     LynxFWIMDataPtr                pLynxFWIMData;
  9942.     LynxRegistersPtr            pLynxRegs;
  9943.     OSStatus                    status = noErr;
  9944.     UInt32                        dmaChannelNum;
  9945.  
  9946.     // Get our engine data and FWIM data.
  9947.     status = FWGetDCLProgramEngineData
  9948.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  9949.     if (status == noErr)
  9950.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  9951.  
  9952.     // Get base address of Lynx registers.
  9953.     if (status == noErr)
  9954.         pLynxRegs = pLynxFWIMData->pLynxRegisters;
  9955.  
  9956.     // Start the DMA engine.
  9957.     if (status == noErr)
  9958.     {
  9959.         // Figure out what DMA channel is used by this DCL
  9960.         dmaChannelNum = 0;
  9961.         while( dmaChannelNum < kNumDMAChannels ) {
  9962.             if( pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram == dclProgramID )
  9963.                 break;
  9964.             dmaChannelNum++;
  9965.         }
  9966.         
  9967.         SynchronizeIO();// • Damn Compiler Bug!
  9968.         if( dmaChannelNum < kNumDMAChannels ) {
  9969.         
  9970.             // Load a physical address
  9971.             pLynxRegs->dmaChannel[dmaChannelNum].curPCLAddr =
  9972.                 EndianSwap32Bit ((UInt32) pLynxDCLCompilerEngineData->pStartPCL->refCon);
  9973.             SynchronizeIO ();
  9974.     
  9975.             // Set ready, CH ENA, and Link bits to enable DMA.
  9976.             pLynxRegs->dmaChannel[dmaChannelNum].ready =
  9977.                 EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
  9978.             SynchronizeIO ();
  9979.     
  9980.             pLynxRegs->dmaChannel[dmaChannelNum].control =
  9981.                 EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  9982.             SynchronizeIO ();
  9983.             
  9984.             // Enable receive comparator.
  9985.             status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  9986.                         (UInt32 *) &pLynxRegs->dmaComparator[dmaChannelNum].mask1,
  9987.                         (UInt32)EndianSwapImm32Bit (kLynxEN_CH_COMPARE));
  9988.             SynchronizeIO ();
  9989.         }
  9990.         else 
  9991.             status = channelNotAvailableErr;    // Should never happen, I think.
  9992.     }
  9993.  
  9994.     return (status);
  9995. }
  9996.  
  9997.  
  9998. ////////////////////////////////////////////////////////////////////////////////
  9999. //
  10000. // LynxFWIMStopTalkingDCLProgram
  10001. //
  10002. //   This routine stops running the given DCL program.
  10003. //
  10004.  
  10005. static OSStatus LynxFWIMStopTalkingDCLProgram(
  10006.     DCLProgramID                dclProgramID)
  10007. {
  10008.     LynxDCLCompilerEngineDataPtr
  10009.                                 pLynxDCLCompilerEngineData;
  10010.     LynxFWIMDataPtr                pLynxFWIMData;
  10011.     LynxRegistersPtr            pLynxRegs;
  10012. #ifdef DMA_FLUSH_CODE
  10013. #if DMA_FLUSH_CODE
  10014.     UInt32                        linkFIFO, pciFIFO, waitForFIFO;
  10015.     UInt32                        linkFIFO1, pciFIFO1;
  10016. #endif
  10017. #endif
  10018.     OSStatus                    status = noErr;
  10019.     UInt32                        dmaChannelNum;
  10020.  
  10021.     // Get our engine data and FWIM data.
  10022.     status = FWGetDCLProgramEngineData
  10023.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  10024.  
  10025.     if (status == noErr)
  10026.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  10027.  
  10028.     // Get base address of Lynx registers.
  10029.     if (status == noErr)
  10030.         pLynxRegs = pLynxFWIMData->pLynxRegisters;
  10031.  
  10032.     // Stop the DMA engine.
  10033.     if (status == noErr)
  10034.     {
  10035.         // Figure out what DMA channel is used by this DCL
  10036.         dmaChannelNum = 0;
  10037.         while( dmaChannelNum < kNumDMAChannels ) {
  10038.             if( pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram == dclProgramID )
  10039.                 break;
  10040.             dmaChannelNum++;
  10041.         }
  10042.         
  10043.         SynchronizeIO();// • Damn Compiler Bug! If this isn't here the value of dmaChannelNum gets munged.
  10044.         if( dmaChannelNum < kNumDMAChannels ) {
  10045.         
  10046.             // Removed unnecessary pre-REV A code to deal with PHY JAMs
  10047.             //zzz Read quad out of ITF FIFO to clear underflow jams.
  10048.             //pLynxFWIMData->bitBucket = pLynxRegs->itfPopPush0;
  10049.     
  10050.             // Clear the Ready bit.  Each transmit PCL has a wait-for-ready,
  10051.             // so the DMA will pause before the start of the next packet.
  10052.             pLynxRegs->dmaChannel[dmaChannelNum].ready = EndianSwapImm32Bit (0);
  10053.             SynchronizeIO ();
  10054.                     
  10055.             // In very unusual circumstances, it could be a long time until the DMA
  10056.             // stops.  For example, we could have preloaded 30 or 40 cycles of tiny
  10057.             // packets (say, header only with zero payload) and now we're trying to
  10058.             // send one really big packet (larger than the FIFO).  Because the IT DMA
  10059.             // tries to work ahead, it will be loading that big packet a little at a
  10060.             // time, as room becomes available in the FIFO.  That could take 30 or 40
  10061.             // cycles before the DMA finishes the current command and can pause.
  10062.     
  10063.             // To be sure the pause really took effect, wait here until the IT FIFO
  10064.             // is empty.  If the FIFO is full because we can't transmit, this would
  10065.             // wait forever, so also bail out if we wait too long.
  10066.             // zzz should use real time, not one million loops.
  10067.     
  10068.             // A better way to do this would be to arrange for an interrupt.
  10069.             // But that's complicated - one would have to rewrite part of the
  10070.             // PCL to interrupt and halt, then resume it, then exit here, then
  10071.             // take the interrupt, then clean up the PCL (which might be reused later).
  10072.     
  10073.             // For now we will just wait 2ms. This way we don't have to access registers
  10074.             // which might not be safe if the PHY is unpowered or missing. This is
  10075.             // not completly sufficient for the pathological case described above but
  10076.             // will work fine for DV and all known existing clients.
  10077.  
  10078. #ifdef DMA_FLUSH_CODE
  10079. #if DMA_FLUSH_CODE
  10080.             waitForFIFO = 1000000;
  10081.             while (waitForFIFO && !status )
  10082.             {
  10083.                 waitForFIFO--;
  10084.                 
  10085.                 status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  10086.                         (UInt32 *) &pLynxRegs->pciFifoPort,            // !!! original code used linkFifoPort! Was this a bug? Seems like it
  10087.                         (UInt32 *) &pciFIFO);                        
  10088.                 
  10089.                 // DMA can't access the linkFifoPort register without hosing the Link chip! For now use
  10090.                 // the processor on the theory that we just successfully got pciFifoPort data without
  10091.                 // a problem and that it should still be OK. Long term we want to find a better way to
  10092.                 // do this.
  10093.                 if( !status ) {
  10094.                 //    status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  10095.                 //            (UInt32 *) &pLynxRegs->linkFifoPort,
  10096.                 //            (UInt32 *) &linkFIFO);
  10097.                 
  10098.                     linkFIFO = pLynxRegs->linkFifoPort;
  10099.                 
  10100.                 }
  10101.                 
  10102.                 linkFIFO = EndianSwap32Bit (linkFIFO);
  10103.                 pciFIFO = EndianSwap32Bit (pciFIFO);
  10104.  
  10105.                 // The mask checks both the FIFO index and the "wrap-around" bit.
  10106.                 // They both have to be equal if the FIFO is empty.  If they are
  10107.                 // equal, make sure they are also unchanged.  If either of them
  10108.                 // "moved", try again.
  10109.                 
  10110.                 if ((linkFIFO && 0x04ff0000) == (pciFIFO && 0x04ff0000))
  10111.                 {
  10112.  
  10113.                     if( !status ) {
  10114.                     
  10115.                         status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  10116.                                 (UInt32 *) &pLynxRegs->pciFifoPort,            // !!! original code used linkFifoPort! Was this a bug? Seems like it
  10117.                                 (UInt32 *) &pciFIFO1);                        
  10118.                     }
  10119.                                         
  10120.                     // DMA can't access the linkFifoPort register without hosing the Link chip! For now use
  10121.                     // the processor on the theory that we just successfully got pciFifoPort data without
  10122.                     // a problem and that it should still be OK. Long term we want to find a better way to
  10123.                     // do this.
  10124.                     if( !status ) {
  10125.                     //    status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  10126.                     //            (UInt32 *) &pLynxRegs->linkFifoPort,
  10127.                     //            (UInt32 *) &linkFIFO1);
  10128.                     
  10129.                         linkFIFO1 = pLynxRegs->linkFifoPort;
  10130.                     
  10131.                     }
  10132.                             
  10133.                     if ((linkFIFO == EndianSwap32Bit (linkFIFO1)) &&
  10134.                         (pciFIFO == EndianSwap32Bit (pciFIFO1)))
  10135.                         waitForFIFO = 0;
  10136.                 }
  10137.             }
  10138. #else
  10139.             // Just wait a while rather than poking on registers which might crash the
  10140.             // machine. See comment block above.
  10141.             DelayForHardware(DurationToAbsolute(durationMillisecond * 2));
  10142. #endif
  10143. #endif
  10144.             
  10145.             // DMA must be idle by now, so it's safe to turn it off.
  10146.             pLynxRegs->dmaChannel[dmaChannelNum].control &=
  10147.                 ~EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  10148.             SynchronizeIO ();
  10149.             
  10150. #ifdef LynxFireBug
  10151. {
  10152.     UInt32 temp;
  10153.     
  10154.     if( !status ) {
  10155.         status = LynxFWIMSafeRegisterRead( pLynxFWIMData,
  10156.             (UInt32 *) &pLynxRegs->fifoOverUnderErrorCounters,
  10157.             (UInt32 *) &temp );
  10158.         temp = EndianSwap32Bit (temp );
  10159.         
  10160.         sprintf (fireBug, "LynxFWIM:  FIFO stats during iso tx:  ITF_UNDER %ld,  ATF_UNDER %ld,  GRF_OVER %ld",
  10161.                  (temp >> 16) & 0xff, (temp >> 8) & 0xff, temp & 0xff);
  10162.         LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  10163.     }
  10164. }
  10165. #endif    
  10166.         }
  10167.         else 
  10168.             status = channelNotAvailableErr;    // Should never happen, I think.
  10169.     }
  10170.  
  10171.     return (status);
  10172. }
  10173.  
  10174.  
  10175. ////////////////////////////////////////////////////////////////////////////////
  10176. //
  10177. // LynxFWIMStopListeningDCLProgram
  10178. //
  10179. //   This routine stops running the given DCL program.
  10180. //
  10181.  
  10182. static OSStatus LynxFWIMStopListeningDCLProgram(
  10183.     DCLProgramID                dclProgramID)
  10184. {
  10185.     LynxDCLCompilerEngineDataPtr
  10186.                                 pLynxDCLCompilerEngineData;
  10187.     LynxFWIMDataPtr                pLynxFWIMData;
  10188.     LynxRegistersPtr            pLynxRegs;
  10189.     OSStatus                    status = noErr;
  10190.     UInt32                        dmaChannelNum;
  10191.  
  10192.     // Get our engine data and FWIM data.
  10193.     status = FWGetDCLProgramEngineData
  10194.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  10195.     if (status == noErr)
  10196.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  10197.  
  10198.     // Get base address of Lynx registers.
  10199.     if (status == noErr)
  10200.         pLynxRegs = pLynxFWIMData->pLynxRegisters;
  10201.  
  10202.     // Stop the DMA engine.
  10203.     if (status == noErr)
  10204.     {
  10205.         // Figure out what DMA channel is used by this DCL
  10206.         dmaChannelNum = 0;
  10207.         while( dmaChannelNum < kNumDMAChannels ) {
  10208.             if( pLynxFWIMData->DMAInfo[dmaChannelNum].dclProgram == dclProgramID )
  10209.                 break;
  10210.             dmaChannelNum++;
  10211.         }
  10212.         
  10213.         SynchronizeIO();// • Damn Compiler Bug! If this isn't here the value of dmaChannelNum gets munged.
  10214.         if( dmaChannelNum < kNumDMAChannels ) {
  10215.             // Disable channel comparator.
  10216.             //zzz need way to bit bucket any remaining packets in FIFO
  10217.             status = LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  10218.                         (UInt32 *) &pLynxRegs->dmaComparator[dmaChannelNum].mask1,
  10219.                         (UInt32) 0);
  10220.             SynchronizeIO ();
  10221.         }
  10222.         else
  10223.             status = channelNotAvailableErr;    // Should never happen, I think.
  10224.     }
  10225.  
  10226.     return (status);
  10227. }
  10228.  
  10229.  
  10230. ////////////////////////////////////////////////////////////////////////////////
  10231. //
  10232. // LynxFWIMReleaseDCLProgram
  10233. //
  10234. //   This routine releases the resources allocated for the given DCL program.
  10235. //
  10236.  
  10237. static OSStatus LynxFWIMReleaseDCLProgram(
  10238.     DCLProgramID                dclProgramID)
  10239. {
  10240.     LynxDCLCompilerEngineDataPtr
  10241.                                 pLynxDCLCompilerEngineData;
  10242.     LynxFWIMDataPtr                pLynxFWIMData;
  10243.     OSStatus                    status = noErr;
  10244.  
  10245.     // Get our engine data and FWIM data.
  10246.     status = FWGetDCLProgramEngineData
  10247.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  10248.     if (status == noErr)
  10249.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  10250.  
  10251.     if (status == noErr)
  10252.     {
  10253.         // Deallocate PCL pools.
  10254.         if (pLynxDCLCompilerEngineData->pLynxPCLPoolDataList != nil)
  10255.         {
  10256.             LynxFWIMDeallocatePCLPools
  10257.                 (pLynxDCLCompilerEngineData->pLynxPCLPoolDataList);
  10258.         }
  10259.         
  10260.         // Release all VM resources
  10261.         // Kind of a hack - we set this to -1 if the PrepareMemoryForIO failed:
  10262.         if (pLynxDCLCompilerEngineData->ioPrep.mappingEntryCount != -1)
  10263.         {
  10264.             status = CheckpointIO (pLynxDCLCompilerEngineData->ioPrep.preparationID, kNilOptions);
  10265.             if (status != noErr)
  10266.             {
  10267.                 sprintf (debugStr, "DCL data CheckpointIO status %ld",
  10268.                          (long) status);
  10269.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  10270.             }
  10271.             PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData->ioPrep.rangeInfo.multipleRanges.rangeTable);
  10272.             PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData->ioPrep.physicalMapping);
  10273.         }
  10274.         
  10275.         // Deallocate engine data.
  10276.         PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData);
  10277.     }
  10278.     
  10279.     return (status);
  10280. }
  10281.  
  10282.  
  10283. ////////////////////////////////////////////////////////////////////////////////
  10284. //
  10285. // LynxFWIMReadRequestTimeoutHandler
  10286. //
  10287. //   This proc will retry a transaction if any more retries are specified.
  10288. //
  10289.  
  10290. static OSStatus    LynxFWIMReadRequestTimeoutHandler(
  10291.     void                        *p1,
  10292.     void                        *p2)
  10293. {
  10294.     FWIMCommandParamsPtr        pFWIMCommandParams;
  10295.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  10296.                                     (FWIMAsynchCommandParamsPtr) p1;
  10297.     LynxFWIMDataPtr                pLynxFWIMData; 
  10298.     UInt32                        commandAcceptance;
  10299.     Boolean                        commandBusy;
  10300.     UInt32                        ackCode, ackType;
  10301.     LynxPCLPtr                    pPCL;
  10302.     OSStatus                    pendingFWIMCommandStatus,
  10303.                                 status = noErr;
  10304.  
  10305. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadRequestTimeoutHandler");
  10306.  
  10307.     // Get our internal data.
  10308.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  10309.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  10310.     pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
  10311.  
  10312.     // Note that timer went off.
  10313.     pLynxFWIMData->requestTimeoutTimerSet = false;
  10314.  
  10315.     // Check if command is still busy.
  10316.     if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  10317.     {
  10318.         commandBusy = true;
  10319.     }
  10320.     else
  10321.     {
  10322.         commandBusy = false;
  10323.         status = pendingFWIMCommandStatus;
  10324.     }
  10325.  
  10326.     // Retry if there are more retries left, otherwise return with timeout
  10327.     // status.
  10328.     if (commandBusy)
  10329.     {
  10330.         
  10331.         // Check to see if the read request was actually received by somebody.
  10332.         // If nobody was home only do one retry.
  10333.         // !!! This assumes that we have only the one AsyncTXPCL AND that nobody
  10334.         // has used it since then. Since this FWIM is pretty single threaded this is
  10335.         // safe for now.
  10336.         pPCL = &pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL];
  10337.         ackCode = (EndianSwap32Bit (pPCL->status) & kLynxAcks) >> kLynxAcksPhase;
  10338.         ackType = ((EndianSwap32Bit (pPCL->status) & kLynxAck_Type) != 0);
  10339.         if (ackType != 0 && ackCode == 1) {        // Special ack 1 (Link Timeout)
  10340.             if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 2)
  10341.                 pFWIMAsynchCommandParams->numRetries = 2;
  10342.         }
  10343.  
  10344.         if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  10345.         {
  10346.             status = LynxFWIMRead (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  10347.         }
  10348.         else
  10349.         {
  10350.             status = timeoutErr;
  10351.         }
  10352.  
  10353.         if (status != noErr)
  10354.             commandBusy = false;
  10355.     }
  10356.  
  10357.     // Complete command if it's no longer busy.
  10358.     if (!commandBusy)
  10359.     {
  10360.         pLynxFWIMData->pPendingFWIMCommand = nil;
  10361.         FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  10362.     }
  10363.  
  10364.     return (status);
  10365. }
  10366.  
  10367.  
  10368. ////////////////////////////////////////////////////////////////////////////////
  10369. //
  10370. // LynxFWIMWriteRequestTimeoutHandler
  10371. //
  10372. //   This proc will retry a transaction if any more retries are specified.
  10373. //zzz Only need this until reset code completes commands manually.
  10374. //zzz need locking mechanism between this routine and the ack int routine.
  10375. //
  10376. // Note - presently unused (not set in LynxFWIMWrite)
  10377.  
  10378. static OSStatus    LynxFWIMWriteRequestTimeoutHandler(
  10379.     void                        *p1,
  10380.     void                        *p2)
  10381. {
  10382.     FWIMCommandParamsPtr        pFWIMCommandParams;
  10383.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  10384.                                     (FWIMAsynchCommandParamsPtr) p1;
  10385.     LynxFWIMDataPtr                pLynxFWIMData; 
  10386.     LynxRegistersPtr            pLynxRegs;
  10387.     Boolean                        commandBusy;
  10388.     OSStatus                    pendingFWIMCommandStatus,
  10389.                                 status = noErr;
  10390.  
  10391. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteRequestTimeoutHandler");
  10392.  
  10393.     // Get our internal data.
  10394.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  10395.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  10396.     pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
  10397.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  10398.  
  10399.     // Note that timer went off.
  10400.     pLynxFWIMData->requestTimeoutTimerSet = false;
  10401.  
  10402.     // Check if command is still busy.
  10403.     if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  10404.     {
  10405.         commandBusy = true;
  10406.     }
  10407.     else
  10408.     {
  10409.         commandBusy = false;
  10410.         status = pendingFWIMCommandStatus;
  10411.     }
  10412.  
  10413.     // Check if ack code indicates a completed transfer.  Retry if it doesn't.
  10414.     if (commandBusy)
  10415.     {
  10416. // NYI
  10417. // Works differently in Lynx - look in DMA/PCL status
  10418.         FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteRequestTimeoutHandler - NYI ###");
  10419. #if 0
  10420.         nodeAddress = EndianSwap32Bit (pLinkRegs->nodeAddress);
  10421.         ackCode =
  10422.             (nodeAddress & kTINodeAddressATAck) >> kTINodeAddressATAckPhase;
  10423.         if (ackCode == kFWAckComplete)
  10424.         {
  10425.             commandBusy = false;
  10426.                 status = noErr;
  10427.             }
  10428.             else
  10429.             {
  10430.             if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  10431.             {
  10432.                 status = LynxFWIMWrite (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  10433.             }
  10434.         else
  10435.         {
  10436.             status = timeoutErr;
  10437.         }
  10438.  
  10439.             if (status != noErr)
  10440.                 commandBusy = false;
  10441.         }
  10442. #endif
  10443.     }
  10444.  
  10445.     // Complete command if it's no longer busy.
  10446.     if (!commandBusy)
  10447.     {
  10448.         pLynxFWIMData->pPendingFWIMCommand = nil;
  10449.         FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  10450.     }
  10451.  
  10452.     return (status);
  10453. }
  10454.  
  10455.  
  10456. ////////////////////////////////////////////////////////////////////////////////
  10457. //
  10458. // LynxFWIMLockRequestTimeoutHandler
  10459. //
  10460. //   This proc will retry a transaction if any more retries are specified.
  10461. //zzz need to check if command is still busy.
  10462. // NYI - Never tested for Lynx
  10463. //
  10464.  
  10465. static OSStatus    LynxFWIMLockRequestTimeoutHandler(
  10466.     void                        *p1,
  10467.     void                        *p2)
  10468. {
  10469.     FWIMCommandParamsPtr        pFWIMCommandParams;
  10470.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  10471.                                     (FWIMAsynchCommandParamsPtr) p1;
  10472.     LynxFWIMDataPtr                pLynxFWIMData; 
  10473.     UInt32                        commandAcceptance;
  10474.     Boolean                        commandBusy;
  10475.     OSStatus                    pendingFWIMCommandStatus,
  10476.                                 status = noErr;
  10477.  
  10478. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMLockRequestTimeoutHandler");
  10479.  
  10480.     // Get our internal data.
  10481.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  10482.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  10483.     pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
  10484.  
  10485.     // Note that timer went off.
  10486.     pLynxFWIMData->requestTimeoutTimerSet = false;
  10487.  
  10488.     // Check if command is still busy.
  10489.     if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  10490.     {
  10491.         commandBusy = true;
  10492.     }
  10493.     else
  10494.     {
  10495.         commandBusy = false;
  10496.         status = pendingFWIMCommandStatus;
  10497.     }
  10498.  
  10499.     // Retry if there are more retries left, otherwise return with timeout
  10500.     // status.
  10501.     if (commandBusy)
  10502.     {
  10503.         if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  10504.         {
  10505.             status = LynxFWIMLock (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  10506.             }
  10507.             else
  10508.             {
  10509.                 status = timeoutErr;
  10510.             }
  10511.  
  10512.         if (status != noErr)
  10513.             commandBusy = false;
  10514.     }
  10515.  
  10516.     // Complete command if it's no longer busy.
  10517.     if (!commandBusy)
  10518.     {
  10519.         pLynxFWIMData->pPendingFWIMCommand = nil;
  10520.         FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  10521.     }
  10522.  
  10523.     return (status);
  10524. }
  10525.  
  10526. ////////////////////////////////////////////////////////////////////////////////
  10527. //
  10528. // LynxFWIMDeferredTaskMultiplexer
  10529. //
  10530. //   Dispatches the deferred task to the appropriate routine based on 
  10531. //   DMAInfo.channelType
  10532. //
  10533.  
  10534. static void    LynxFWIMDeferredTaskMultiplexer(
  10535.     void                        *p1,
  10536.     void                        *p2)
  10537. {
  10538.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  10539.     UInt32                        dmaChannel = (UInt32) p2;
  10540.     
  10541.     pLynxFWIMData->DMAInfo[dmaChannel].lynxDTScheduled = false;
  10542.  
  10543.     switch( pLynxFWIMData->DMAInfo[dmaChannel].channelType ) {
  10544.     
  10545.     case kChannelUnused:
  10546.         break;
  10547.     case kAsyncRcv:
  10548.         LynxFWIMDMAAsyncPCLDeferredTask( p1, p2);
  10549.         break;
  10550.     case kIsochXmit:
  10551.         LynxFWIMDMAIsochTransmitDeferredTask( p1, p2);
  10552.         break;
  10553.     case kIsochRcv:
  10554.         LynxFWIMDMAIsochReceivePCLDeferredTask( p1, p2);
  10555.         break;
  10556.     
  10557.     }
  10558. }
  10559.  
  10560. ////////////////////////////////////////////////////////////////////////////////
  10561. //
  10562. // LynxFWIMDMAAsyncPCLDeferredTask
  10563. //
  10564. //   Dispatches self-ID and async packets after DMA is finished
  10565. //
  10566.  
  10567. static void    LynxFWIMDMAAsyncPCLDeferredTask(
  10568.     void                        *p1,
  10569.     void                        *p2)
  10570. {
  10571.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  10572.     LynxPCLPtr                    pPCL, pSkimPCL, pLastSelfIDsPCL;
  10573.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData, pSkimPCLData;
  10574.     UInt32                        pclStatus, skimStatus;
  10575.     UInt32                        packetSize, skimSize;
  10576.     Ptr                            packetBuffer;
  10577.     UInt32                        quad0, quad1;
  10578.     Boolean                        skimDone;
  10579.     UInt32                        skipCount;
  10580.     static UInt32                skipTotal = 0;
  10581.     OSStatus                    status = noErr;
  10582.  
  10583.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  10584.     
  10585.     // This is part of a temporary hack.
  10586.     // Within 50ms after a bus reset, don't accept any packets.
  10587.     // We'll get called again after these flags are cleared.
  10588.     
  10589.     if ((pLynxFWIMData->delayedResetTimerSet) || (pLynxFWIMData->busResetDTScheduled)) {
  10590.         LynxFWIMEnableVMUserCode(pLynxFWIMData);
  10591.         return;
  10592.     }
  10593.  
  10594.     // Get next PCL to process and its data.
  10595.     pPCL = pLynxFWIMData->pNextAsyncPCL;
  10596.     if (pPCL != nil)
  10597.     {
  10598.         pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  10599.         pclStatus = EndianSwap32Bit (pPCL->status);
  10600.     }
  10601.     else
  10602.     {
  10603.         pclStatus = kLynxInvalidStatus;
  10604.     }
  10605.  
  10606.     pLynxFWIMData->selfIDPackets = 0; // Make sure this is zero coming in.
  10607.  
  10608.     // Process all PCLs with data.
  10609.     while (pclStatus & kLynxPktCmp)
  10610.     {
  10611.         // Set next PCL to process.
  10612.         pLynxFWIMData->pNextAsyncPCL = pLynxAsyncRxPCLData->pNextPCL;
  10613.  
  10614.         // If this packet is self-IDs, and we are running behind, then
  10615.         // there could be *another* packet with self-IDs waiting too.
  10616.         // In that case, we can avoid a bunch of PHY register reads
  10617.         // and other work by just skipping to the last available self-IDs.
  10618.         // The skipped packets can't contain any responses we want, and
  10619.         // we will be unable to reply to any requests during that period,
  10620.         // so we can safely dispose of all of the packets.
  10621.         
  10622.         // In theory it is possible for someone to have sent us a write
  10623.         // request to which we sent ack_complete.  However, because this
  10624.         // write request was sent after a bus reset, and before we had ever
  10625.         // identified ourselves, the sender has no way to know who we are.
  10626.         // So we can safely ignore such a request even if we said ack_complete.
  10627.         
  10628.         // zzz However, if someone sent a *broadcast* write, they might reasonably
  10629.         // except us to (try to) receive it.  If we find a broadcast write while
  10630.         // scanning ahead, we really ought to stop scanning at that point.
  10631.         
  10632.         // Process packet if it had no errors.  Otherwise recycle PCL.
  10633.         if (!(pclStatus & (kLynxMstErr | kLynxPktErr)))
  10634.         {
  10635.  
  10636.             // Get packet buffer and length.
  10637.             packetBuffer = pLynxAsyncRxPCLData->packetBuffer;
  10638.             packetSize = (pclStatus & kLynxTransferredCount) >>
  10639.                          kLynxTransferredCountPhase;
  10640.  
  10641.             // Get first two quads.
  10642.             quad0 = ((UInt32 *) packetBuffer)[0];
  10643.             quad1 = ((UInt32 *) packetBuffer)[1];
  10644.         
  10645.             // If length is zero or first quad is inverse of second quad, assume self-IDs
  10646.             if ((packetSize == 0) || (quad0 == ~quad1))
  10647.             {
  10648.                 // Self-IDs
  10649.                 do {    // while (pLynxFWIMData->selfIDPackets)
  10650.                 
  10651.                     pLastSelfIDsPCL = pSkimPCL = pPCL;
  10652.                     pSkimPCLData = (LynxAsyncRxPCLDataPtr) pSkimPCL->refCon;
  10653.                     skimStatus = EndianSwap32Bit (pPCL->status);
  10654.                     skimDone = false;
  10655.                     
  10656.                     while (skimDone == false)
  10657.                     {
  10658.                         // Move to next PCL
  10659.                         pSkimPCL = pSkimPCLData->pNextPCL;
  10660.                         if (pSkimPCL == nil)
  10661.                         {
  10662.                             // Hit the end of the list
  10663.                             skimDone = true;
  10664.                         }
  10665.                         else
  10666.                         {
  10667.                             pSkimPCLData = (LynxAsyncRxPCLDataPtr) pSkimPCL->refCon;
  10668.                             skimStatus = EndianSwap32Bit (pSkimPCL->status);
  10669.                         }
  10670.                         
  10671.                         if ((skimDone == false) && (skimStatus & kLynxPktCmp))
  10672.                         {
  10673.                             // pSkimPCL points to a PCL that has been executed
  10674.                             // If this one had an error, just keep looking.
  10675.                             if (!(skimStatus & (kLynxMstErr | kLynxPktErr)))
  10676.                             {
  10677.                                 // Get packet buffer and length.
  10678.                                 skimSize = (skimStatus & kLynxTransferredCount) >>
  10679.                                              kLynxTransferredCountPhase;
  10680.                     
  10681.                                 // Get first two quads.
  10682.                                 quad0 = ((UInt32 *) pSkimPCLData->packetBuffer)[0];
  10683.                                 quad1 = ((UInt32 *) pSkimPCLData->packetBuffer)[1];
  10684.                             
  10685.                                 // If length is zero or first quad is inverse of second quad, assume self-IDs
  10686.                                 if ((skimSize == 0) || (quad0 == ~quad1))
  10687.                                 {
  10688.                                     // This is the latest point we can skip ahead to (so far)
  10689.                                     pLastSelfIDsPCL = pSkimPCL;
  10690.                                 }
  10691.                             }
  10692.                         }
  10693.                         else    // ran out of places to look
  10694.                         {
  10695.                             skimDone = true;
  10696.                         }
  10697.                     }
  10698.                     
  10699.                     if (pLastSelfIDsPCL != pPCL)
  10700.                     {
  10701.                         // recycle skipped PCLs and
  10702.                         // set up for alternate
  10703.                         
  10704.                         skipCount = 0;
  10705.                         while (pPCL != pLastSelfIDsPCL)
  10706.                         {
  10707.                             // Add PCL back to active list.
  10708.                             pSkimPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  10709.                             pSkimPCL = pSkimPCLData->pNextPCL;
  10710.                             LynxFWIMAddAsyncRxPCL (pPCL);
  10711.                             pPCL = pSkimPCL;
  10712.                             skipCount++;
  10713.                             skipTotal++;
  10714.                         }
  10715.                         
  10716.                         pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  10717.                         pLynxFWIMData->pNextAsyncPCL = pLynxAsyncRxPCLData->pNextPCL;
  10718.                         pclStatus = EndianSwap32Bit (pPCL->status);
  10719.                         packetBuffer = pLynxAsyncRxPCLData->packetBuffer;
  10720.                         packetSize = (pclStatus & kLynxTransferredCount) >>
  10721.                                      kLynxTransferredCountPhase;
  10722.                         
  10723.                         //sprintf (fireBug, "LynxFWIM: Skipped %ld useless packets [%ld total]",
  10724.                         //         (long) skipCount, (long) skipTotal);
  10725.                         //LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  10726.                     }
  10727.                     
  10728.                     // If we had previously found some self-ID packets then this is the second time
  10729.                     // through here after finding self-IDs. If pPCL still points at what we had
  10730.                     // the last time then no more self-IDs have come in and its safe to tell the
  10731.                     // FSL about our new node ID and bus topology. If pPCL points to something
  10732.                     // different then new self-IDs have come in and since we asked the PHY what
  10733.                     // our node-ID is and we may be out of sync. In this case we start again by
  10734.                     // processing the packet and looping.
  10735.                     
  10736.                     if( pLynxFWIMData->selfIDPackets && pLynxFWIMData->selfIDPackets == pPCL ) {
  10737.                         LynxFWIMInformFSLofSelfIDs( pLynxFWIMData );    // Also recycles PCL
  10738.                         pLynxFWIMData->selfIDPackets = 0;
  10739.                     }
  10740.                     else {
  10741.                         // First time through or we got new selfIDs after processing the packet
  10742.                         if( pLynxFWIMData->selfIDPackets )                    
  10743.                             LynxFWIMAddAsyncRxPCL (pLynxFWIMData->selfIDPackets);
  10744.                         pLynxFWIMData->selfIDPackets = pPCL;
  10745.                         pLynxFWIMData->selfIDPacketBuffer = packetBuffer;
  10746.                         pLynxFWIMData->selfIDPacketSize = packetSize;
  10747.                         
  10748.                         // We have self-ids, so lets go stuff the globals with what the PHY thinks is our
  10749.                         // local node ID and filter out/create our self-ID packet.
  10750.                         LynxFWIMProcessPacket (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  10751.                     }
  10752.                 } while ( pLynxFWIMData->selfIDPackets );
  10753.             }
  10754.             else {
  10755.                 // Process packet if not self-ID.
  10756.                 LynxFWIMProcessPacket (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  10757.             }
  10758.         }
  10759.         else
  10760.         {
  10761.             // Add PCL back to active list.
  10762.             LynxFWIMAddAsyncRxPCL (pPCL);
  10763.         }
  10764.  
  10765.         // Process next PCL.
  10766.         pPCL = pLynxFWIMData->pNextAsyncPCL;
  10767.         if (pPCL != nil)
  10768.         {
  10769.             pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  10770.             pclStatus = EndianSwap32Bit (pPCL->status);
  10771.         }
  10772.         else
  10773.         {
  10774.             pclStatus = kLynxInvalidStatus;
  10775.         }
  10776.     }
  10777.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  10778.  
  10779. }
  10780.  
  10781.  
  10782. ////////////////////////////////////////////////////////////////////////////////
  10783. //
  10784. // LynxFWIMInformFSLofSelfIDs
  10785. //
  10786. //   Calls FWProcessSelfIDs
  10787. //
  10788.  
  10789. static void LynxFWIMInformFSLofSelfIDs(
  10790.     LynxFWIMDataPtr                pLynxFWIMData )
  10791. {
  10792.  
  10793.     FWIMProcessSelfIDsParams    fwimProcessSelfIDsParams;
  10794.     
  10795.     // Process the self IDs.
  10796.     //zzz need to get status.
  10797.     fwimProcessSelfIDsParams.fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  10798.     fwimProcessSelfIDsParams.pSelfIDList = (Ptr) pLynxFWIMData->selfIDPacketBuffer;
  10799.     fwimProcessSelfIDsParams.selfIDListSize = pLynxFWIMData->selfIDPacketSize;
  10800.     fwimProcessSelfIDsParams.pLocalSelfID = (Ptr) pLynxFWIMData->localSelfIDQuads;
  10801.     
  10802.     if( pLynxFWIMData->numPHYPorts > 3 )
  10803.         fwimProcessSelfIDsParams.localSelfIDSize = 8 * (((pLynxFWIMData->numPHYPorts - 4) >> 3) + 2);
  10804.     else
  10805.         fwimProcessSelfIDsParams.localSelfIDSize = 8;
  10806.  
  10807.     fwimProcessSelfIDsParams.processSelfIDsFlags = 0;
  10808.     FWProcessSelfIDs (&fwimProcessSelfIDsParams);
  10809.     
  10810.     pLynxFWIMData->generation = fwimProcessSelfIDsParams.generation;
  10811.     pLynxFWIMData->generationValid = true;
  10812.  
  10813.     // We used to load the nodeID register here, but this was a bad place to
  10814.     // do it.  That's now done based on PHY register receive interrupts.
  10815.     
  10816.     // Add PCL back to active list.
  10817.     LynxFWIMAddAsyncRxPCL (pLynxFWIMData->selfIDPackets);
  10818.     
  10819.     pLynxFWIMData->selfIDPackets = 0;
  10820.  
  10821.  
  10822. }
  10823. ////////////////////////////////////////////////////////////////////////////////
  10824. //
  10825. // LynxFWIMDMAIsochReceivePCLDeferredTask
  10826. //
  10827. //   Handles PCL interrupts for isochronous receive.
  10828. //
  10829.  
  10830. static void    LynxFWIMDMAIsochReceivePCLDeferredTask(
  10831.     void                        *p1,
  10832.     void                        *p2)
  10833. {
  10834.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  10835.     UInt32                        dmaChannel = (UInt32) p2;
  10836.     LynxIsochPortDataPtr        pLynxIsochPortData;
  10837.     static LynxDCLProgramInterruptQueueElementPtr
  10838.                                 pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
  10839.     LynxDCLProgramInterruptQueueElementPtr
  10840.                                 pDCLInterrupt,
  10841.                                 pDCLFirstInterrupt,
  10842.                                 pPrevDCLInterrupt;
  10843.     DCLCommandPtr                pDCLCommand;
  10844.     DCLCallProcPtr                pDCLCallProc;
  10845.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  10846.     UInt32                        numInterrupts;
  10847.     OSStatus                    status = noErr;
  10848.  
  10849.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  10850.     
  10851.     // Get isoch port data.
  10852.     pLynxIsochPortData = pLynxFWIMData->lynxIsochPortDataList[dmaChannel];
  10853.  
  10854.     // Get and clear interrupt queue tail.
  10855.     pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[dmaChannel];
  10856.     while (!CompareAndSwap
  10857.                 ((UInt32) pDCLInterrupt,
  10858.                  nil,
  10859.                  (UInt32 *) &(pLynxFWIMData->pDCLInterruptTail[dmaChannel])))
  10860.     {
  10861.         pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[dmaChannel];
  10862.     }
  10863.  
  10864.     // remember for later
  10865.     pDCLFirstInterrupt = pDCLInterrupt;
  10866.  
  10867.     // Build interrupt list and clear interrupts.
  10868.     numInterrupts = 0;
  10869.     while ((pDCLInterrupt != nil) && (numInterrupts < 10))
  10870.     {
  10871.         pDCLInterruptList[numInterrupts] = pDCLInterrupt;
  10872.         pPrevDCLInterrupt = pDCLInterrupt->pPrevDCLInterrupt;
  10873.         pDCLInterrupt->pPrevDCLInterrupt = nil;
  10874.         numInterrupts++;
  10875.  
  10876.         pDCLInterrupt = pPrevDCLInterrupt;
  10877.     }
  10878.  
  10879.     /////////////////////////////////
  10880.     // There is an occasional case where the list of DCLs to be serviced can become slightly corrupt.
  10881.     // The case is:
  10882.     //    the DMA reads the value from the tail register
  10883.     //    the defered task sets the tail to nil
  10884.     //    the DMA sets the tail to the current DCL to be serviced
  10885.     // This causes the newest DCL serviced during one deferred task to be the last DCL serviced during
  10886.     // the next deferred task.  Instead of preventing this case.  We just look for its results and undo
  10887.     // them.
  10888.     
  10889.     if( ( numInterrupts > 1) 
  10890.         && ( pDCLInterruptList[numInterrupts - 1] == pLynxFWIMData->pDCLLastInterrupt[dmaChannel] ) )
  10891.         numInterrupts--;
  10892.     
  10893.     // save for corruption case
  10894.     pLynxFWIMData->pDCLLastInterrupt[dmaChannel] = pDCLFirstInterrupt;
  10895.     
  10896.     /////////////////////////////////
  10897.  
  10898.     // Run through interrupt queue.
  10899.     while (numInterrupts--)
  10900.     {
  10901.         // Get DCL command that caused interrupt.
  10902.         pDCLCommand = pDCLInterruptList[numInterrupts]->pDCLCommand;
  10903.  
  10904.         // Dispatch off of opcode.
  10905.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  10906.         {
  10907.             case kDCLCallProcOp :
  10908.                 // Call the proc.
  10909.                 pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  10910.                 FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
  10911.                 break;
  10912.  
  10913.             case kDCLUpdateDCLListOp :
  10914.                 // Update the DCL list.
  10915.                 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  10916.                 LynxFWIMDCLCompilerUpdateNotification (pLynxIsochPortData->dclProgramID,
  10917.                                                        pDCLUpdateDCLList->dclCommandList,
  10918.                                                        pDCLUpdateDCLList->numDCLCommands);
  10919.                 break;
  10920.  
  10921.             default :
  10922.                 break;
  10923.         }
  10924.     }
  10925.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  10926. }
  10927.  
  10928.  
  10929. ////////////////////////////////////////////////////////////////////////////////
  10930. //
  10931. // LynxFWIMDMAIsochTransmitDeferredTask
  10932. //
  10933. //   Handles PCL interrupts for isochronous transmit.
  10934. //
  10935.  
  10936. static void    LynxFWIMDMAIsochTransmitDeferredTask(
  10937.     void                        *p1,
  10938.     void                        *p2)
  10939. {
  10940.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  10941.     UInt32                        dmaChannel = (UInt32) p2;
  10942.     LynxIsochPortDataPtr        pLynxIsochPortData;
  10943.     static LynxDCLProgramInterruptQueueElementPtr
  10944.                                 pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
  10945.     LynxDCLProgramInterruptQueueElementPtr
  10946.                                 pDCLInterrupt,
  10947.                                 pDCLFirstInterrupt,
  10948.                                 pPrevDCLInterrupt;
  10949.     DCLCommandPtr                pDCLCommand;
  10950.     DCLCallProcPtr                pDCLCallProc;
  10951.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  10952.     UInt32                        numInterrupts;
  10953.     OSStatus                    status = noErr;
  10954.  
  10955.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  10956.  
  10957.     // Get isoch port data.
  10958.     pLynxIsochPortData = pLynxFWIMData->lynxIsochPortDataList[dmaChannel];
  10959.  
  10960.     // Get and clear interrupt queue tail.
  10961.     pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[dmaChannel];
  10962.     while (!CompareAndSwap
  10963.                 ((UInt32) pDCLInterrupt,
  10964.                  nil,
  10965.                  (UInt32 *) &(pLynxFWIMData->pDCLInterruptTail[dmaChannel])))
  10966.     {
  10967.         pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[dmaChannel];
  10968.     }
  10969.  
  10970.     // remember for later
  10971.     pDCLFirstInterrupt = pDCLInterrupt;
  10972.     
  10973.     // Build interrupt list and clear interrupts.
  10974.     numInterrupts = 0;
  10975.     while ((pDCLInterrupt != nil) && (numInterrupts < 10))
  10976.     {
  10977.         pDCLInterruptList[numInterrupts] = pDCLInterrupt;
  10978.         pPrevDCLInterrupt = pDCLInterrupt->pPrevDCLInterrupt;
  10979.         pDCLInterrupt->pPrevDCLInterrupt = nil;
  10980.         numInterrupts++;
  10981.  
  10982.         pDCLInterrupt = pPrevDCLInterrupt;
  10983.     }
  10984.  
  10985.     /////////////////////////////////
  10986.     // There is an occasional case where the list of DCLs to be serviced can become slightly corrupt.
  10987.     // The case is:
  10988.     //    the DMA reads the value from the tail register
  10989.     //    the defered task sets the tail to nil
  10990.     //    the DMA sets the tail to the current DCL to be serviced
  10991.     // This causes the newest DCL serviced during one deferred task to be the last DCL serviced during
  10992.     // the next deferred task.  Instead of preventing this case.  We just look for its results and undo
  10993.     // them.
  10994.     
  10995.     if( ( numInterrupts > 1) 
  10996.         && ( pDCLInterruptList[numInterrupts - 1] == pLynxFWIMData->pDCLLastInterrupt[dmaChannel] ) )
  10997.         numInterrupts--;
  10998.     
  10999.     // save for corruption case
  11000.     pLynxFWIMData->pDCLLastInterrupt[dmaChannel] = pDCLFirstInterrupt;
  11001.  
  11002.     /////////////////////////////////
  11003.     
  11004.     // Run through interrupt queue.
  11005.     while (numInterrupts--)
  11006.     {
  11007.         // Get DCL command that caused interrupt.
  11008.         pDCLCommand = pDCLInterruptList[numInterrupts]->pDCLCommand;
  11009.  
  11010.         // Dispatch off of opcode.
  11011.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  11012.         {
  11013.             case kDCLCallProcOp :
  11014.                 // Call the proc.
  11015.                 pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  11016.                 FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
  11017.                 break;
  11018.  
  11019.             case kDCLUpdateDCLListOp :
  11020.                 // Update the DCL list.
  11021.                 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  11022.                 LynxFWIMDCLCompilerUpdateNotification (pLynxIsochPortData->dclProgramID,
  11023.                                                        pDCLUpdateDCLList->dclCommandList,
  11024.                                                        pDCLUpdateDCLList->numDCLCommands);
  11025.                 break;
  11026.  
  11027.             default :
  11028.                 break;
  11029.         }
  11030.     }
  11031. }
  11032.  
  11033.  
  11034. ////////////////////////////////////////////////////////////////////////////////
  11035. //
  11036. // LynxFWIMResetDeferredTask
  11037. //
  11038. //   This proc deals with bus resets at FireWire deferred task time.
  11039. //
  11040.  
  11041. static void    LynxFWIMResetDeferredTask(
  11042.     void                        *p1,
  11043.     void                        *p2)
  11044. {
  11045.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  11046.     AbsoluteTime                timeoutAbsolute;
  11047.     OSStatus                    status = noErr;
  11048.  
  11049. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMResetDeferredTask");
  11050.     
  11051.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  11052.  
  11053.     // Bus reset DT no longer scheduled.
  11054.     pLynxFWIMData->busResetDTScheduled = false;
  11055.  
  11056.     // This is a temporary hack.  We want to reduce the risk of PHY jams.
  11057.     // So after a bus reset, before we process the self-IDs, wait 50ms to
  11058.     // allow another bus reset (if any) to arrive.  When this timer goes
  11059.     // off, if busResetDTScheduled has become true again, then there was
  11060.     // another bus reset.  By the time we get to the self-IDs for the first
  11061.     // reset, we'll be able to skip forward over them and avoid some PHY
  11062.     // register accesses.
  11063.     
  11064.     // If there are more resets beyond 50ms, we won't keep waiting - otherwise
  11065.     // we might hang if there were endless resets.  But hopefully we will have
  11066.     // managed to skip some of them.
  11067.  
  11068.     if (pLynxFWIMData->delayedResetTimerSet == false)
  11069.     {
  11070.         timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (50 * durationMillisecond));
  11071.         status = SetInterruptTimer
  11072.                     (&timeoutAbsolute,
  11073.                      LynxFWIMDelayedReset,
  11074.                      pLynxFWIMData,
  11075.                      &(pLynxFWIMData->delayedResetTimerID));
  11076.         if (status == noErr)
  11077.             pLynxFWIMData->delayedResetTimerSet = true;
  11078.             else LynxFWIMDelayedReset (p1, nil);            // Might as well proceed (should never happen)
  11079.     }
  11080.     
  11081.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  11082.  
  11083. }
  11084.  
  11085.  
  11086. static OSStatus    LynxFWIMDelayedReset(
  11087.     void                        *p1,
  11088.     void                        *p2)
  11089. {
  11090.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  11091.     LynxRegistersPtr            pLynxRegs;
  11092.  
  11093.     pLynxFWIMData->delayedResetTimerSet = false;
  11094.  
  11095.     // Get base address of Lynx registers.
  11096.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  11097.  
  11098.     // Re-enable data transmission.
  11099.     LynxFWIMSetLinkControlBits
  11100.         (pLynxFWIMData,
  11101.          EndianSwapImm32Bit( kLynxTX_ASYNC_EN ));
  11102.  
  11103.     // If there's a pending FWIM command, set its status to busReconfiguredErr.
  11104.     //zzz should we do this here, or in services?
  11105.     //zzz this probably should not be done on all types of commands.
  11106.     if (pLynxFWIMData->pPendingFWIMCommand)
  11107.     {
  11108.         if (pLynxFWIMData->pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  11109.             pLynxFWIMData->pendingFWIMCommandStatus = busReconfiguredErr;
  11110.     }
  11111.     
  11112.     // During the period that delayedResetTimerSet was true,
  11113.     // no async packets were processed.
  11114.     // Now (another hack) process any that are waiting:
  11115.         
  11116.     LynxFWIMHandleDMAInterrupt (pLynxFWIMData, pLynxFWIMData->asyncRxDMA);
  11117.  
  11118.     return noErr;
  11119. }
  11120.  
  11121.  
  11122. ////////////////////////////////////////////////////////////////////////////////
  11123. //
  11124. // LynxFWIMHoldoffResetRequests
  11125. //
  11126. //   This proc handles bus reset holdoff timer expiring. Check if any bus reset
  11127. //     requests are pending and complete them.
  11128. //
  11129.  
  11130. static OSStatus    LynxFWIMHoldoffResetRequests(
  11131.     void                        *p1,
  11132.     void                        *p2)
  11133. {
  11134.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  11135.     UInt32                            commandAcceptance;
  11136.     UInt32                            i;
  11137.     OSStatus                        status = noErr;
  11138.     
  11139.     // turn off timer set flag
  11140.     pLynxFWIMData->holdoffResetRequestsTimerSet = false;
  11141.     
  11142.     // if a bus reset request came in during the timer period, issue the request request
  11143.     for (i=0;i<kPendingResetRequestsAllowed;i++)
  11144.     {
  11145.         if (pLynxFWIMData->pResetRequestList[i].inUse)
  11146.         {
  11147.             status = LynxFWIMResetBus(pLynxFWIMData->pResetRequestList[i].pPendingResetRequest, &commandAcceptance);
  11148.             pLynxFWIMData->pResetRequestList[i].inUse = false;
  11149.             FWIMCommandIsComplete (pLynxFWIMData->pResetRequestList[i].pPendingResetRequest->fwimCommandID, status);
  11150.             break;
  11151.         }
  11152.     }
  11153.     
  11154.     // if more than one bus reset request came in during the timer period,
  11155.     // complete them with the status from the above LynxFWIMResetBus
  11156.     for (i=0;i<kPendingResetRequestsAllowed;i++)
  11157.     {
  11158.         if (pLynxFWIMData->pResetRequestList[i].inUse)
  11159.         {
  11160.             pLynxFWIMData->pResetRequestList[i].inUse = false;
  11161.             FWIMCommandIsComplete (pLynxFWIMData->pResetRequestList[i].pPendingResetRequest->fwimCommandID, status);
  11162.         }
  11163.     }
  11164.     
  11165.     return noErr;
  11166. }
  11167.  
  11168.  
  11169. ////////////////////////////////////////////////////////////////////////////////
  11170. //
  11171. // LynxFWIMMiscInterruptDeferredTask
  11172. //
  11173. //   This proc deals with miscellaneous interrupts at FireWire deferred task time.
  11174. //
  11175.  
  11176. static void    LynxFWIMMiscInterruptDeferredTask(
  11177.     void                        *p1,
  11178.     void                        *p2)
  11179. {
  11180.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  11181.     UInt32                        i;
  11182.  
  11183.     LynxFWIMDisableVMUserCode(pLynxFWIMData);
  11184.  
  11185.     // DT no longer scheduled.
  11186.     pLynxFWIMData->miscInterruptDTScheduled = false;
  11187.  
  11188.     i = pLynxFWIMData->miscInterrupt;
  11189.     pLynxFWIMData->miscInterrupt = 0;
  11190.  
  11191. #ifdef LynxFireBug
  11192.     sprintf (fireBug, "LynxFWIM:  Interrupts: %s%s%s%s%s%s%s%s%s%s",
  11193.              (i & kLynxPHY_TIME_OUT)    ? "PHY_TO "        : "",
  11194.              (i & kLynxIT_STUCK)        ? "IT_STUCK "    : "",
  11195.              (i & kLynxAT_STUCK)        ? "AT_STUCK "    : "",
  11196.              (i & kLynxHDR_ERR)            ? "CRC_ERR "    : "",
  11197.              (i & kLynxTC_ERR)            ? "TC_ERR "        : "",
  11198.              (i & kLynxCYC_LOST)        ? "CYC_LOST "    : "",
  11199.              (i & kLynxCYC_ARB_FAILED)    ? "CYC_ARB "    : "",
  11200.              (i & kLynxITF_UNDER_FLOW)    ? "ITF_UF "        : "",
  11201.              (i & kLynxATF_UNDER_FLOW)    ? "ATF_UF "        : "",
  11202.              (i & kLynxIARB_FAILED)        ? "IARB "        : "");
  11203.     //if (i) LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  11204. #endif
  11205.  
  11206.     LynxFWIMEnableVMUserCode(pLynxFWIMData);
  11207. }
  11208.  
  11209.  
  11210. ////////////////////////////////////////////////////////////////////////////////
  11211. //
  11212. // LynxFWIMAckSecondaryInterruptHandler
  11213. //
  11214. //   This proc checks the ack received for the sent transaction.  If the ack
  11215. // specifies a completed transaction, this proc will complete the transaction.
  11216. // If the ack specifies an error, this proc will retry the transaction.
  11217. //zzz need to handle response pending ack.
  11218. //zzz need locking mechanism between this routine and the timeout routine
  11219. //
  11220. // We aren't called by interrupt, we're called directly by LynxFWIMWrite()
  11221.  
  11222. static OSStatus    LynxFWIMAckSecondaryInterruptHandler(
  11223.     void                        *p1,
  11224.     void                        *p2)
  11225. {
  11226.     FWIMCommandParamsPtr        pFWIMCommandParams;
  11227.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  11228.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1; 
  11229.     LynxPCLPtr                    pPCL = (LynxPCLPtr) p2;
  11230.     AbsoluteTime                timeoutAbsolute;
  11231.     UInt32                        ackCode, ackType, tryAgain;
  11232.     Boolean                        commandBusy;
  11233.     OSStatus                    pendingFWIMCommandStatus,
  11234.                                 status = noErr;
  11235.  
  11236. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMAckSecondaryInterruptHandler");
  11237.  
  11238.     // Get our internal data.
  11239.     pFWIMAsynchCommandParams =
  11240.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  11241.     pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
  11242.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  11243.  
  11244.     // Make sure pending command is a write.
  11245.     if (pFWIMCommandParams->commandType == kFWIMWrite)
  11246.     {
  11247.         if (status == noErr)
  11248.         {
  11249.             // Check if command is still busy.
  11250.             if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  11251.             {
  11252.                 commandBusy = true;
  11253.             }
  11254.             else
  11255.             {
  11256.                 commandBusy = false;
  11257.                 status = pendingFWIMCommandStatus;
  11258.             }
  11259.     
  11260.             // Check if ack code indicates a completed transfer.  Retry if it doesn't.
  11261.             if (commandBusy)
  11262.             {
  11263.                 ackCode = (EndianSwap32Bit (pPCL->status) & kLynxAcks) >> kLynxAcksPhase;
  11264.                 ackType = ((EndianSwap32Bit (pPCL->status) & kLynxAck_Type) != 0);
  11265.                 tryAgain = 0;
  11266.                 
  11267.                 if (ackType == 0)        // Normal 1394 ack
  11268.                 {
  11269.                     if ((ackCode == kFWAckComplete) || (ackCode == kFWAckPending))
  11270.                     {
  11271.                         // This happens the majority of the time.
  11272.                         //zzz should wait for write response when ack pending
  11273.                         commandBusy = false;
  11274.                     }
  11275.                     else if (ackCode != kFWAckTypeError)
  11276.                     {
  11277.                         // This should only be AckDataError, meaning the packet we sent
  11278.                         // failed CRC at the receiver.  However, non-revA parts seem to
  11279.                         // yield ack 0 in this case.  So except for TypeError, just try
  11280.                         // again.  TypeError will probably fail again if we try again,
  11281.                         // so give up in that case.
  11282.                         tryAgain = 1;
  11283.                     }
  11284.                     else        // TypeError
  11285.                     {
  11286.                         commandBusy = false;
  11287.                         status = retryExceededErr;    //zzz do we have a better error code?
  11288.                     }
  11289.                 }
  11290.                 else                    // Some Lynx error code, not a real ack
  11291.                 {
  11292.                     if ((ackCode == 0) || (ackCode == 1))
  11293.                     {
  11294.                         // 0 indicates retry overrun (too many retries)
  11295.                         // 1 indicates Link Timeout - meaning nobody home.  Assume no Link at that Phy.
  11296.                         status = retryExceededErr;
  11297.                         commandBusy = false;
  11298.                     }
  11299.                     else if (ackCode == 2)
  11300.                     {
  11301.                         // 2 indicates FIFO underrun.  This happens sometimes.
  11302.                         // Just try again.
  11303.                         // zzz should only retry a limited number of times.
  11304.                         tryAgain = 1;
  11305.                     }
  11306.                     else    // unknown ackCode. zzz should retry some of these, needs more study
  11307.                     {
  11308.                         status = retryExceededErr;
  11309.                         commandBusy = false;
  11310.                     }
  11311.                 }
  11312.             }
  11313.                 
  11314.             if (tryAgain)
  11315.             {
  11316.                     timeoutAbsolute =
  11317.                         AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (10 * durationMillisecond));
  11318.                     status = SetInterruptTimer
  11319.                                 (&timeoutAbsolute,
  11320.                                  LynxFWIMWriteTimer,
  11321.                                  pFWIMAsynchCommandParams,
  11322.                                  &(pLynxFWIMData->requestTimeoutTimerID));
  11323.                     if (status == noErr)
  11324.                         pLynxFWIMData->requestTimeoutTimerSet = true;
  11325.     
  11326.                 if (status != noErr)
  11327.                     commandBusy = false;
  11328.             }
  11329.             
  11330.             // Complete command if it's no longer busy.
  11331.             if (!commandBusy)
  11332.             {
  11333.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  11334.                 FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  11335.             }
  11336.         }
  11337.     }
  11338.  
  11339.     return (status);
  11340. }
  11341.  
  11342.  
  11343. ////////////////////////////////////////////////////////////////////////////////
  11344. //
  11345. // LynxFWIMProcessPacket
  11346. //
  11347. //   Dispatch packet processing based on tCode (async or isoch).
  11348. //zzz check destID???
  11349. //
  11350.  
  11351. static void LynxFWIMProcessPacket(
  11352.     LynxFWIMDataPtr                pLynxFWIMData,
  11353.     LynxPCLPtr                    pPCL,
  11354.     Ptr                            packetBuffer,
  11355.     UInt32                        packetSize)
  11356. {
  11357.     UInt32                        tCode;
  11358.     UInt32                        ackCode;
  11359.     UInt32                        pclStatus;
  11360.     UInt32                        quad0, quad1;
  11361.             
  11362.     // If we received any packet, then the GRF is not jammed.
  11363.     // This will prevent us from suspecting otherwise by mistake.
  11364.     pLynxFWIMData->lastARDMA = 0;
  11365.  
  11366.     // Get first two quads.
  11367.     quad0 = ((UInt32 *) packetBuffer)[0];
  11368.     quad1 = ((UInt32 *) packetBuffer)[1];
  11369.  
  11370.     // Compute tCode.  If length is zero or first quad is inverse of second quad,
  11371.     // set tCode to special self ID tCode.
  11372.     if ((packetSize == 0) || (quad0 == ~quad1))
  11373.         tCode = kLynxTCodeSelfID;
  11374.     else
  11375.         tCode = (quad0 & kFWPacketTCode) >> kFWPacketTCodePhase;
  11376.  
  11377.     if (tCode != kLynxTCodeSelfID)
  11378.     {
  11379.         pclStatus = EndianSwap32Bit (pPCL->status);
  11380.         ackCode = (pclStatus & kLynxAcks) >> kLynxAcksPhase;
  11381.         if ((ackCode != 1) && (ackCode != 2))
  11382.         {
  11383.             tCode = 0x0f;    // reserved
  11384.             
  11385.             //sprintf (fireBug, "LynxFWIM: Whoops, ack %ld in received packet [%08lx]",
  11386.             //         (long) ackCode, (long) pclStatus);
  11387.             //LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  11388.         }
  11389.     }
  11390.     
  11391.     // Dispatch processing based on tCode.
  11392.     switch (tCode)
  11393.     {
  11394.         case kFWTCodeWriteQuadlet :
  11395.             LynxFWIMProcessWriteQuadletPacket
  11396.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11397.             break;
  11398.  
  11399.         case kFWTCodeWriteBlock :
  11400.             LynxFWIMProcessWriteBlockPacket
  11401.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11402.             break;
  11403.  
  11404.         case kFWTCodeWriteResponse :
  11405.             LynxFWIMProcessWriteResponsePacket
  11406.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11407.             break;
  11408.  
  11409.         case kFWTCodeReadQuadlet :
  11410.             LynxFWIMProcessReadQuadletPacket
  11411.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11412.             break;
  11413.  
  11414.         case kFWTCodeReadBlock :
  11415.             LynxFWIMProcessReadBlockPacket
  11416.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11417.             break;
  11418.  
  11419.         case kFWTCodeReadQuadletResponse :
  11420.             LynxFWIMProcessReadQuadletResponsePacket
  11421.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11422.             break;
  11423.  
  11424.         case kFWTCodeReadBlockResponse :
  11425.             LynxFWIMProcessReadBlockResponsePacket
  11426.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11427.             break;
  11428.  
  11429.         case kFWTCodeLock :
  11430.             LynxFWIMProcessLockPacket
  11431.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11432.             break;
  11433.  
  11434.         case kFWTCodeIsochronousBlock :
  11435.             LynxFWIMProcessIsochronousBlockPacket
  11436.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11437.             break;
  11438.  
  11439.         case kFWTCodeLockResponse :
  11440.             LynxFWIMProcessLockResponsePacket
  11441.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11442.             break;
  11443.  
  11444.  
  11445.         // This is now a bit different. We don't so much handle the
  11446.         // self ID packets as prepare the AsyncRXDT to handle it. We 
  11447.         // just look at the PHY registers and build up the local self-id
  11448.         // and stuff it into the globals. After checking that no additional
  11449.         // self-id packets came in then the AsyncRXDT can deal with
  11450.         // telling FSL about the packet.
  11451.         case kLynxTCodeSelfID :
  11452.             LynxFWIMProcessSelfIDPacket
  11453.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  11454.             break;
  11455.  
  11456.         default :
  11457.             LynxFWIMAddAsyncRxPCL (pPCL);
  11458.             break;
  11459.     }
  11460. }
  11461.  
  11462.  
  11463. ////////////////////////////////////////////////////////////////////////////////
  11464. //
  11465. // LynxFWIMProcessSelfIDPacket
  11466. //
  11467. //   This proc tries to process a selfID packet.
  11468. //zzz Should validate selfIDs by making sure the phyID is correct , there's
  11469. //zzz enough of them, etc.  Need to generate CRC. Should cancel timeout timer.
  11470. //
  11471. // This whole function has a basic race condition. The physical ID in the PHY
  11472. // register is not tied to the self-id packets we recieved. In the case of the 
  11473. // older Phys where we always gen the local self-id from the PHY registers we
  11474. // at least know the local self-id packet is correct. What we don't know is 
  11475. // whether we got a reset since we last grabbed self-id packets. If we did
  11476. // then the list of external self-id packets may also have a packet for our
  11477. // node ID. The correct set of self-id packets should then be in the PCL.
  11478. //
  11479. // The newer 1394a PHYs complicate the problem further. They include the local
  11480. // self-id packet in the list provided to the link layer. With the current FSL
  11481. // API we need to strip it out. Note that this could be mean stripping out
  11482. // multiple self-id packets if we have more than 3 ports.
  11483. //
  11484. // More complications: Accessing the PHY registers may trigger the dreaded PHY
  11485. // jam problem. To avoid this the best thing would be to use the self-id we
  11486. // stripped from the total set and use that. Problem is this could be from a
  11487. // different node entirely if the PHY register and the self-id list are out
  11488. // of sync.
  11489. //
  11490. // To solve these issues we don't really do much processing of the packets here.
  11491. // Mostly we build up our own self-id packets for the FSL. On newer PHYs this 
  11492. // involves removing the self-id from the packetBuffer which is why we still 
  11493. // have it here.
  11494.  
  11495. static void    LynxFWIMProcessSelfIDPacket(
  11496.     LynxFWIMDataPtr                pLynxFWIMData,
  11497.     LynxPCLPtr                    pPCL,
  11498.     Ptr                            packetBuffer,
  11499.     UInt32                        packetSize)
  11500. {
  11501.     LynxRegistersPtr            pLynxRegs;
  11502.     UInt32                        localSelfID;
  11503.     UInt32                        physicalID;
  11504.     UInt32                        packetPhysID;
  11505.     UInt32                        gapCount;                        
  11506.     UInt32                        speed;
  11507.     UInt32                        contender;
  11508.     UInt32                        portStatus;
  11509.     UInt32                        * sQuad;
  11510.     UInt32                        localSelfIDSize;
  11511.     UInt32                        numQuads;
  11512.     UInt32                        portNum;
  11513.     UInt32                        portOffset;
  11514.     UInt32                        packetNum;
  11515.     Boolean                        foundUs;
  11516.  
  11517.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  11518.  
  11519.     ////////////////////////////////////////////////////////////////////////////
  11520.     //
  11521.     // Build our local selfID.
  11522.     //
  11523.  
  11524. //    FWDebugStr ((ConstStr255Param) "\pSelfID proceeding");
  11525.  
  11526.     if( pLynxFWIMData->receiveLocalSelfID ) {
  11527.     
  11528.         // Get physical ID .
  11529.         
  11530.         physicalID = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxExtPhyPhysicalIDAddress);
  11531.         if (physicalID & kLynxExtPhyR)
  11532.             pLynxFWIMData->root = true;
  11533.         else
  11534.             pLynxFWIMData->root = false;
  11535.         physicalID = (physicalID & kLynxExtPhyPhysicalID) >> kLynxExtPhyPhysicalIDPhase;
  11536.  
  11537.         // This will have already been done by the PhyReg primary interrupt handler.
  11538.         // But do it again here just to be safe (there is a possible race condition)
  11539.         
  11540.         // Disable cycle mastering if we're not root.
  11541.         if (!pLynxFWIMData->root)
  11542.         {
  11543.             LynxFWIMClearLinkControlBits
  11544.                 (pLynxFWIMData, EndianSwap32Bit( kLynxCYCMASTER ));
  11545.         }
  11546.  
  11547.         // Now go find it in the list of self-ids and remove it.
  11548.         sQuad = (UInt32 *) packetBuffer;
  11549.         foundUs = false;
  11550.         numQuads = packetSize >> 2;
  11551.         
  11552.         while( numQuads ) {
  11553.         
  11554.             // Only check the quad if it is the first quad in a self-id packet
  11555.             if( !( *sQuad & kFWSelfIDPacketType) ) {
  11556.                 packetPhysID = (*sQuad & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase;
  11557.                 if( packetPhysID == physicalID ) {
  11558.                     foundUs = true;
  11559.                     break;
  11560.                 }
  11561.             }
  11562.             sQuad += 2;    // Skip over inverse of node.
  11563.             numQuads -= 2;
  11564.         }
  11565.         if( foundUs ) {
  11566.         
  11567.             if( pLynxFWIMData->numPHYPorts > 3 )
  11568.                 localSelfIDSize = 8 * (((pLynxFWIMData->numPHYPorts - 4) >> 3) + 2);
  11569.             else
  11570.                 localSelfIDSize = 8;
  11571.             BlockMove( (Ptr) sQuad, &pLynxFWIMData->localSelfIDQuads, localSelfIDSize);
  11572.             BlockMove( (Ptr) sQuad + localSelfIDSize, (Ptr) sQuad, ((UInt32) packetBuffer + packetSize) - ((UInt32) sQuad + localSelfIDSize));
  11573.             pLynxFWIMData->selfIDPacketSize -= localSelfIDSize;
  11574.         }
  11575.         
  11576.     }
  11577.     else {
  11578.  
  11579.         // Get physical ID and root bit.
  11580.         physicalID = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyPhysicalIDAddress);
  11581.         if (physicalID & kLynxPhyR)
  11582.             pLynxFWIMData->root = true;
  11583.         else
  11584.             pLynxFWIMData->root = false;
  11585.         physicalID = (physicalID & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
  11586.         localSelfID = physicalID << kFWSelfIDPhyIDPhase;
  11587.         
  11588.         // This will have already been done by the PhyReg primary interrupt handler.
  11589.         // But do it again here just to be safe (there is a possible race condition)
  11590.         
  11591.         // Disable cycle mastering if we're not root.
  11592.         if (!pLynxFWIMData->root)
  11593.         {
  11594.             LynxFWIMClearLinkControlBits
  11595.                 (pLynxFWIMData, EndianSwapImm32Bit( kLynxCYCMASTER ));
  11596.         }
  11597.         
  11598.         // Get gap count.
  11599.         gapCount = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyGCAddress);
  11600.         gapCount = (gapCount & kLynxPhyGC) >> kLynxPhyGCPhase;
  11601.         localSelfID |= gapCount << kFWSelfID0GapCntPhase;
  11602.         
  11603.         // Get speed.
  11604.         speed = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhySPDAddress);
  11605.         speed = (speed & kLynxPhySPD) >> kLynxPhySPDPhase;
  11606.         localSelfID |= speed << kFWSelfID0SPPhase;
  11607.         
  11608.         // Get speed.
  11609.         contender = EndianSwap32Bit (pLynxRegs->gpioData[0]);
  11610.         if (contender & 1)
  11611.             localSelfID |= kFWSelfID0C;
  11612.         /*zzz should do it like this. */
  11613.         #if 0
  11614.         contender = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyCAddress);    /* This won't work if the PHY has >3 ports! */
  11615.         if (contender & kLynxPhyC)
  11616.             localSelfID |= kFWSelfID0C;
  11617.         #endif
  11618.         
  11619.         for( portNum = 0; portNum < 3; portNum++ ) {
  11620.  
  11621.             // Get port status p0.
  11622.             portStatus = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyPortStatusAddress + portNum);
  11623.             if (portStatus & kLynxPhyCon)
  11624.             {
  11625.                 if (portStatus & kLynxPhyCh)
  11626.                     localSelfID |= ((kFWSelfIDPortStatusChild << kFWSelfID0P0Phase) >> (portNum << 1));
  11627.                 else
  11628.                     localSelfID |= ((kFWSelfIDPortStatusParent << kFWSelfID0P0Phase) >> (portNum << 1));
  11629.             }
  11630.             else
  11631.             {
  11632.                 localSelfID |= ((kFWSelfIDPortStatusNotConnected << kFWSelfID0P0Phase) >> (portNum << 1));
  11633.             }
  11634.         }
  11635.                 
  11636.         // Set selfID packet ID, link active, self powered and power class.
  11637.         // HardwarePowerClass is a macro from the top of this file.
  11638.  
  11639.         localSelfID |= ((kFWSelfIDPacketID << kFWPhyPacketIDPhase) |
  11640.                         kFWSelfID0L |
  11641.                         (HardwarePowerClass << kFWSelfID0PwrPhase));
  11642.         
  11643.         // If more than 1 packet, say so                
  11644.         if( pLynxFWIMData->numPHYPorts > 3 )
  11645.             localSelfID |= kFWSelfIDMore;
  11646.             
  11647.         pLynxFWIMData->localSelfIDQuads[0] = localSelfID;
  11648.         pLynxFWIMData->localSelfIDQuads[1] = ~localSelfID;
  11649.  
  11650.         // Fill in extra self-id packets if necessary.
  11651.         packetNum = 0;
  11652.         portOffset = 0;
  11653.         for( portNum = 3; portNum < pLynxFWIMData->numPHYPorts; portNum++ ) {
  11654.             if( portNum == 3 || portNum == 11 || portNum == 19 ) {
  11655.                 
  11656.                 // Create quads for previous self-ID packet if necessary
  11657.                 if( packetNum > 0 ) {
  11658.                     localSelfID |= kFWSelfIDMore;
  11659.                     pLynxFWIMData->localSelfIDQuads[packetNum << 1] = localSelfID;
  11660.                     pLynxFWIMData->localSelfIDQuads[(packetNum << 1) + 1] = ~localSelfID;
  11661.                 }
  11662.                 packetNum++;
  11663.                 portOffset = 0;
  11664.                 localSelfID = (physicalID << kFWSelfIDPhyIDPhase) |
  11665.                                 (kFWSelfIDPacketID << kFWPhyPacketIDPhase) | kFWSelfIDPacketType |
  11666.                                 ((packetNum - 1) << kFWSelfIDNNPhase);
  11667.             }
  11668.             portStatus = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyPortStatusAddress + portNum);
  11669.             if (portStatus & kLynxPhyCon)
  11670.             {
  11671.                 if (portStatus & kLynxPhyCh)
  11672.                     localSelfID |= ((kFWSelfIDPortStatusChild << kFWSelfIDNPaPhase) >> (portOffset << 1));
  11673.                 else
  11674.                     localSelfID |= ((kFWSelfIDPortStatusParent << kFWSelfIDNPaPhase) >> (portOffset << 1));
  11675.             }
  11676.             else
  11677.             {
  11678.                 localSelfID |= ((kFWSelfIDPortStatusNotConnected << kFWSelfIDNPaPhase) >> (portOffset << 1));
  11679.             }
  11680.             portOffset++;
  11681.         }
  11682.         if( packetNum ) {
  11683.             pLynxFWIMData->localSelfIDQuads[packetNum << 1] = localSelfID;
  11684.             pLynxFWIMData->localSelfIDQuads[(packetNum << 1) + 1] = ~localSelfID;
  11685.         }
  11686.     }
  11687.  
  11688. }
  11689.  
  11690.  
  11691. ////////////////////////////////////////////////////////////////////////////////
  11692. //
  11693. // LynxFWIMProcessWriteQuadletPacket
  11694. //
  11695. //   This proc processes a write quadlet packet.
  11696. //
  11697.  
  11698. static void    LynxFWIMProcessWriteQuadletPacket(
  11699.     LynxFWIMDataPtr                pLynxFWIMData,
  11700.     LynxPCLPtr                    pPCL,
  11701.     Ptr                            packetBuffer,
  11702.     UInt32                        packetSize)
  11703. {
  11704.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  11705.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  11706.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  11707.     UInt32                        pclStatus;
  11708.     UInt32                        transactionStatus;
  11709.  
  11710. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessWriteQuadletPacket");
  11711.  
  11712.     // Get PCL data.
  11713.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  11714.  
  11715.     // Fill in processing params.
  11716.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  11717.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  11718.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  11719.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  11720.         LynxFWIMProcessWriteQuadletRequestCompletionProc;
  11721.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  11722.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  11723.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);
  11724.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  11725.     BlockCopy (packetBuffer,
  11726.                &(pFWIMProcessAsynchParams->destinationID),
  11727.                3 * sizeof (UInt32));
  11728.     pFWIMProcessAsynchParams->length = 4;
  11729.     pFWIMProcessAsynchParams->extendedTCode = 0;
  11730.  
  11731.     pclStatus = EndianSwap32Bit (pPCL->status);
  11732.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  11733.                         kFWTransactionStatusAckCodePhase;
  11734.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  11735.                          kFWTransactionStatusSpeedPhase;
  11736.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  11737.  
  11738.     // Process the write request.
  11739.     FWProcessWriteRequest (pFWIMProcessAsynchParams);
  11740. }
  11741.  
  11742.  
  11743. ////////////////////////////////////////////////////////////////////////////////
  11744. //
  11745. // LynxFWIMProcessWriteQuadletRequestCompletionProc
  11746. //
  11747. //   This proc will be called upon completion of write request processing.
  11748. //
  11749.  
  11750. static void    LynxFWIMProcessWriteQuadletRequestCompletionProc(
  11751.     FWIMProcessParamsPtr        pFWIMProcessParams)
  11752. {
  11753.     LynxPCLPtr                    pPCL;
  11754.  
  11755.     // Get PCL pointer.
  11756.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  11757.  
  11758.     // Add PCL back to active list.
  11759.     LynxFWIMAddAsyncRxPCL (pPCL);
  11760. }
  11761.  
  11762.  
  11763. ////////////////////////////////////////////////////////////////////////////////
  11764. //
  11765. // LynxFWIMProcessWriteBlockPacket
  11766. //
  11767. //   This proc processes a write block packet.
  11768. //
  11769.  
  11770. static void    LynxFWIMProcessWriteBlockPacket(
  11771.     LynxFWIMDataPtr                pLynxFWIMData,
  11772.     LynxPCLPtr                    pPCL,
  11773.     Ptr                            packetBuffer,
  11774.     UInt32                        packetSize)
  11775. {
  11776.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  11777.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  11778.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  11779.     UInt32                        pclStatus;
  11780.     UInt32                        transactionStatus;
  11781.  
  11782. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessWriteBlockPacket");
  11783.         
  11784.     // Get PCL data.
  11785.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  11786.  
  11787.     // Fill in processing params.
  11788.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  11789.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  11790.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  11791.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  11792.         LynxFWIMProcessWriteBlockRequestCompletionProc;
  11793.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  11794.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  11795.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);
  11796.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  11797.     BlockCopy (packetBuffer,
  11798.                &(pFWIMProcessAsynchParams->destinationID),
  11799.                4 * sizeof (UInt32));
  11800.  
  11801.     pclStatus = EndianSwap32Bit (pPCL->status);
  11802.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  11803.                         kFWTransactionStatusAckCodePhase;
  11804.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  11805.                          kFWTransactionStatusSpeedPhase;
  11806.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  11807.  
  11808.     // Process the write request.
  11809.     FWProcessWriteRequest (pFWIMProcessAsynchParams);
  11810. }
  11811.  
  11812.  
  11813. ////////////////////////////////////////////////////////////////////////////////
  11814. //
  11815. // LynxFWIMProcessWriteBlockRequestCompletionProc
  11816. //
  11817. //   This proc will be called upon completion of write request processing.
  11818. //
  11819.  
  11820. static void    LynxFWIMProcessWriteBlockRequestCompletionProc(
  11821.     FWIMProcessParamsPtr        pFWIMProcessParams)
  11822. {
  11823.     LynxPCLPtr                    pPCL;
  11824.  
  11825.     // Get PCL pointer.
  11826.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  11827.  
  11828.     // Add PCL back to active list.
  11829.     LynxFWIMAddAsyncRxPCL (pPCL);
  11830. }
  11831.  
  11832.  
  11833. ////////////////////////////////////////////////////////////////////////////////
  11834. //
  11835. // LynxFWIMProcessWriteResponsePacket
  11836. //
  11837. //   This proc processes a write quadlet response packet.
  11838. //zzz Verify destinationID, and sourceID.
  11839. //
  11840. // NYI - never tested (never happens? same in TIFWIM)
  11841.  
  11842. static void    LynxFWIMProcessWriteResponsePacket(
  11843.     LynxFWIMDataPtr                pLynxFWIMData,
  11844.     LynxPCLPtr                    pPCL,
  11845.     Ptr                            packetBuffer,
  11846.     UInt32                        packetSize)
  11847. {
  11848. #if 0
  11849.     LynxRegistersPtr            pLynxRegs;
  11850.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  11851.     UInt32                        *pPacket;
  11852.     UInt32                        commandType;
  11853.     UInt32                        tLabel;
  11854.     AbsoluteTime                timeRemaining;
  11855.     OSStatus                    status = noErr;
  11856. #endif
  11857.  
  11858. //    FWDebugStr ((ConstStr255Param) "\pNYI LynxFWIMProcessWriteResponsePacket");
  11859. #if 0
  11860.     // Get pointer to link registers.
  11861.     pLinkRegs = (TILinkRegistersPtr) (pLynxFWIMData->regBaseAddress +
  11862.                                       kTILinkRegistersOffset);
  11863.  
  11864.     // Read in rest of packet.
  11865.     pPacket = (UInt32 *) packetBuffer;
  11866.     pPacket++;
  11867.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  11868.     SynchronizeIO ();
  11869.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  11870.     SynchronizeIO ();
  11871.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  11872.     SynchronizeIO ();
  11873.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  11874.     SynchronizeIO ();
  11875.  
  11876.     pPacket = (UInt32 *) packetBuffer;
  11877.  
  11878.     // Get the pending FWIM command if there is one.
  11879.     pFWIMAsynchCommandParams =
  11880.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  11881.  
  11882.     // We must have a pending write command and a matching transaction label.
  11883.     if (pFWIMAsynchCommandParams != nil)
  11884.     {
  11885.         // Get pending command type and transaction label for this packet.
  11886.         commandType =
  11887.             pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  11888.         tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
  11889.  
  11890.         if ((commandType == kFWIMWrite) &&
  11891.             (tLabel == pLynxFWIMData->transactionLabel) &&
  11892.             ((pLynxFWIMData->tCode == kFWTCodeWriteQuadlet) ||
  11893.              (pLynxFWIMData->tCode == kFWTCodeWriteBlock)))
  11894.         {
  11895.             // Try to cancel timeout timer.
  11896.             status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
  11897.                                   &timeRemaining);
  11898.  
  11899.             // Complete command if we didn't time out.
  11900.             if (status == noErr)
  11901.             {
  11902.                 // Finish up command.
  11903.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  11904.                 FWIMCommandIsComplete(pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, noErr);
  11905.             }
  11906.         }
  11907.     }
  11908. #endif
  11909.  
  11910.     // Add PCL back to active list.
  11911.     LynxFWIMAddAsyncRxPCL (pPCL);
  11912. }
  11913.  
  11914.  
  11915. ////////////////////////////////////////////////////////////////////////////////
  11916. //
  11917. // LynxFWIMProcessReadQuadletPacket
  11918. //
  11919. //   This proc processes a read quadlet packet.
  11920. //
  11921.  
  11922. static void    LynxFWIMProcessReadQuadletPacket(
  11923.     LynxFWIMDataPtr                pLynxFWIMData,
  11924.     LynxPCLPtr                    pPCL,
  11925.     Ptr                            packetBuffer,
  11926.     UInt32                        packetSize)
  11927. {
  11928.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  11929.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  11930.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  11931.     UInt32                        pclStatus;
  11932.     UInt32                        transactionStatus;
  11933.  
  11934.     // Get PCL data.
  11935.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  11936.  
  11937.     // Fill in processing params.
  11938.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  11939.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  11940.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  11941.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  11942.         LynxFWIMProcessReadQuadletRequestCompletionProc;
  11943.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  11944.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  11945.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);//zzz should probably be nil.
  11946.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  11947.     BlockCopy (packetBuffer,
  11948.                &(pFWIMProcessAsynchParams->destinationID),
  11949.                3 * sizeof (UInt32));
  11950.     pFWIMProcessAsynchParams->length = 4;
  11951.     pFWIMProcessAsynchParams->extendedTCode = 0;
  11952.     pclStatus = EndianSwap32Bit (pPCL->status);
  11953.  
  11954.     pclStatus = EndianSwap32Bit (pPCL->status);
  11955.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  11956.                         kFWTransactionStatusAckCodePhase;
  11957.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  11958.                          kFWTransactionStatusSpeedPhase;
  11959.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  11960.  
  11961.     // Process the read request.
  11962.     FWProcessReadRequest (pFWIMProcessAsynchParams);
  11963. }
  11964.  
  11965.  
  11966. ////////////////////////////////////////////////////////////////////////////////
  11967. //
  11968. // LynxFWIMProcessReadQuadletRequestCompletionProc
  11969. //
  11970. //   This proc will be called upon completion of read request processing.
  11971. //
  11972.  
  11973. static void    LynxFWIMProcessReadQuadletRequestCompletionProc(
  11974.     FWIMProcessParamsPtr        pFWIMProcessParams)
  11975. {
  11976.     LynxPCLPtr                    pPCL;
  11977.  
  11978.     // Get PCL pointer.
  11979.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  11980.  
  11981.     // Add PCL back to active list.
  11982.     LynxFWIMAddAsyncRxPCL (pPCL);
  11983. }
  11984.  
  11985.  
  11986. ////////////////////////////////////////////////////////////////////////////////
  11987. //
  11988. // LynxFWIMProcessReadBlockPacket
  11989. //
  11990. //   This proc processes a read block packet.
  11991. //
  11992.  
  11993. static void    LynxFWIMProcessReadBlockPacket(
  11994.     LynxFWIMDataPtr                pLynxFWIMData,
  11995.     LynxPCLPtr                    pPCL,
  11996.     Ptr                            packetBuffer,
  11997.     UInt32                        packetSize)
  11998. {
  11999.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  12000.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  12001.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  12002.     UInt32                        pclStatus;
  12003.     UInt32                        transactionStatus;
  12004.  
  12005.     // Get PCL data.
  12006.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  12007.  
  12008.     // Fill in processing params.
  12009.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  12010.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  12011.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  12012.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  12013.         LynxFWIMProcessReadBlockRequestCompletionProc;
  12014.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  12015.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  12016.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz should probably be nil
  12017.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  12018.     BlockCopy (packetBuffer,
  12019.                &(pFWIMProcessAsynchParams->destinationID),
  12020.                4 * sizeof (UInt32));
  12021.  
  12022.     pclStatus = EndianSwap32Bit (pPCL->status);
  12023.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  12024.                         kFWTransactionStatusAckCodePhase;
  12025.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  12026.                          kFWTransactionStatusSpeedPhase;
  12027.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  12028.  
  12029.     // Process the read request.    
  12030.     FWProcessReadRequest (pFWIMProcessAsynchParams);
  12031. }
  12032.  
  12033.  
  12034. ////////////////////////////////////////////////////////////////////////////////
  12035. //
  12036. // LynxFWIMProcessReadBlockRequestCompletionProc
  12037. //
  12038. //   This proc will be called upon completion of read request processing.
  12039. //
  12040.  
  12041. static void    LynxFWIMProcessReadBlockRequestCompletionProc(
  12042.     FWIMProcessParamsPtr        pFWIMProcessParams)
  12043. {
  12044.     LynxPCLPtr                    pPCL;
  12045.  
  12046.     // Get PCL pointer.
  12047.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  12048.  
  12049.     // Add PCL back to active list.
  12050.     LynxFWIMAddAsyncRxPCL (pPCL);
  12051. }
  12052.  
  12053.  
  12054. ////////////////////////////////////////////////////////////////////////////////
  12055. //
  12056. // LynxFWIMProcessReadQuadletResponsePacket
  12057. //
  12058. //   This proc processes a read quadlet response packet.
  12059. //zzz Verify destinationID, and sourceID.
  12060. //
  12061.  
  12062. static void    LynxFWIMProcessReadQuadletResponsePacket(
  12063.     LynxFWIMDataPtr                pLynxFWIMData,
  12064.     LynxPCLPtr                    pPCL,
  12065.     Ptr                            packetBuffer,
  12066.     UInt32                        packetSize)
  12067. {
  12068.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  12069.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  12070.     UInt32                        commandType;
  12071.     UInt32                        tLabel;
  12072.     UInt32                        rCode;
  12073.     UInt32                        *commandBuffer;
  12074.     AbsoluteTime                timeRemaining;
  12075.     OSStatus                    status = noErr,
  12076.                                 responseStatus = noErr;
  12077.  
  12078. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessReadQuadletResponsePacket");
  12079.  
  12080.     // Get the pending FWIM command if there is one.
  12081.     pFWIMAsynchCommandParams =
  12082.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  12083.  
  12084.     // We must have a pending read command and a matching transaction label.
  12085.     if (pFWIMAsynchCommandParams != nil)
  12086.     {
  12087.         // Get pending command type, transaction label, and response code for this packet.
  12088.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  12089.         tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
  12090.         rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
  12091.  
  12092.         if ((commandType == kFWIMRead) &&
  12093.             (tLabel == pLynxFWIMData->transactionLabel) &&
  12094.             (pLynxFWIMData->tCode == kFWTCodeReadQuadlet))
  12095.         {
  12096.             // Try to cancel timeout timer.
  12097.             status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
  12098.                                   &timeRemaining);
  12099.  
  12100.             // Complete command if we didn't time out.
  12101.             if (status == noErr)
  12102.             {
  12103.                 // Fill in command buffer.
  12104.                 if (rCode == kFWResponseComplete)
  12105.                 {
  12106.                     commandBuffer = (UInt32 *) pFWIMAsynchCommandParams->buffer;
  12107.                     *commandBuffer = pPacket[3];
  12108.                 }
  12109.                 else
  12110.                 {
  12111.                     responseStatus = accessErr;//zzz not always the best
  12112.                 }
  12113.     
  12114.                 // Finish up command.
  12115.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  12116.                 FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, responseStatus);
  12117.             }
  12118.         }
  12119.     }
  12120.  
  12121.     // Add PCL back to active list.
  12122.     LynxFWIMAddAsyncRxPCL (pPCL);
  12123. }
  12124.  
  12125.  
  12126. ////////////////////////////////////////////////////////////////////////////////
  12127. //
  12128. // LynxFWIMProcessReadBlockResponsePacket
  12129. //
  12130. //   This proc processes a read block response packet.
  12131. //zzz Verify destinationID, and sourceID.
  12132. //zzz Must check extended tCode.
  12133. //zzz Must return actual number of bytes transferred.
  12134. //
  12135. // NYI - never tested with Lynx
  12136.  
  12137. static void    LynxFWIMProcessReadBlockResponsePacket(
  12138.     LynxFWIMDataPtr                pLynxFWIMData,
  12139.     LynxPCLPtr                    pPCL,
  12140.     Ptr                            packetBuffer,
  12141.     UInt32                        packetSize)
  12142. {
  12143.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  12144.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  12145.     UInt32                        commandType;
  12146.     UInt32                        tLabel;
  12147.     UInt32                        rCode;
  12148.     UInt32                        dataLength;
  12149.     AbsoluteTime                timeRemaining;
  12150.     OSStatus                    status = noErr,
  12151.                                 responseStatus = noErr;
  12152.  
  12153. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessReadBlockResponsePacket");
  12154.  
  12155.     dataLength = (((UInt32 *) packetBuffer)[3] & kFWAsynchDataLength) >>
  12156.                   kFWAsynchDataLengthPhase;
  12157.     
  12158.     // Get the pending FWIM command if there is one.
  12159.     pFWIMAsynchCommandParams =
  12160.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  12161.  
  12162.     // We must have a pending read command and a matching transaction label.
  12163.     if (pFWIMAsynchCommandParams != nil)
  12164.     {
  12165.         // Get pending command type, transaction label, and response code for this packet.
  12166.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  12167.         tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
  12168.         rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
  12169.  
  12170.         if ((commandType == kFWIMRead) &&
  12171.             (tLabel == pLynxFWIMData->transactionLabel) &&
  12172.             (pLynxFWIMData->tCode == kFWTCodeReadBlock))
  12173.         {
  12174.             // Try to cancel timeout timer.
  12175.             status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
  12176.                                   &timeRemaining);
  12177.  
  12178.             // Complete command if we didn't time out.
  12179.             if (status == noErr)
  12180.             {
  12181.                 // Fill in command buffer.
  12182.                 if (rCode == kFWResponseComplete)
  12183.                 {
  12184.                     if (dataLength > pFWIMAsynchCommandParams->length)
  12185.                         dataLength = pFWIMAsynchCommandParams->length;
  12186.                     BlockCopy (&(pPacket[4]),
  12187.                                pFWIMAsynchCommandParams->buffer,
  12188.                                dataLength);
  12189.                 }
  12190.                 else
  12191.                 {
  12192.                     responseStatus = accessErr;//zzz not always the best
  12193.                 }
  12194.  
  12195.                 // Finish up command.
  12196.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  12197.                 FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, responseStatus);
  12198.             }
  12199.         }
  12200.     }
  12201.  
  12202.     // Add PCL back to active list.
  12203.     LynxFWIMAddAsyncRxPCL (pPCL);
  12204. }
  12205.  
  12206.  
  12207. ////////////////////////////////////////////////////////////////////////////////
  12208. //
  12209. // LynxFWIMProcessLockPacket
  12210. //
  12211. //   This proc processes a lock packet.
  12212. //
  12213.  
  12214. static void    LynxFWIMProcessLockPacket(
  12215.     LynxFWIMDataPtr                pLynxFWIMData,
  12216.     LynxPCLPtr                    pPCL,
  12217.     Ptr                            packetBuffer,
  12218.     UInt32                        packetSize)
  12219. {
  12220.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  12221.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  12222.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  12223.     UInt32                        pclStatus;
  12224.     UInt32                        transactionStatus;
  12225.  
  12226.     // Get PCL data.
  12227.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  12228.  
  12229.     // Fill in processing params.
  12230.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  12231.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  12232.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  12233.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  12234.         LynxFWIMProcessLockRequestCompletionProc;
  12235.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  12236.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  12237.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz receive and transmit buffers should be different
  12238.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  12239.     BlockCopy (packetBuffer,
  12240.                &(pFWIMProcessAsynchParams->destinationID),
  12241.                4 * sizeof (UInt32));
  12242.  
  12243.     pclStatus = EndianSwap32Bit (pPCL->status);
  12244.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  12245.                         kFWTransactionStatusAckCodePhase;
  12246.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  12247.                          kFWTransactionStatusSpeedPhase;
  12248.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  12249.  
  12250.     // Process the lock request.
  12251.     FWProcessLockRequest (pFWIMProcessAsynchParams);
  12252. }
  12253.  
  12254.  
  12255. ////////////////////////////////////////////////////////////////////////////////
  12256. //
  12257. // LynxFWIMProcessLockRequestCompletionProc
  12258. //
  12259. //   This proc will be called upon completion of lock request processing.
  12260. //
  12261.  
  12262. static void    LynxFWIMProcessLockRequestCompletionProc(
  12263.     FWIMProcessParamsPtr        pFWIMProcessParams)
  12264. {
  12265.     LynxPCLPtr                    pPCL;
  12266.  
  12267.     // Get PCL pointer.
  12268.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  12269.  
  12270.     // Add PCL back to active list.
  12271.     LynxFWIMAddAsyncRxPCL (pPCL);
  12272. }
  12273.  
  12274.  
  12275. ////////////////////////////////////////////////////////////////////////////////
  12276. //
  12277. // LynxFWIMProcessIsochronousBlockPacket
  12278. //
  12279. //   This proc processes an isochronous block packet.
  12280. //zzz Verify destinationID, and sourceID.
  12281. //zzz need to determine which port this packet is for.
  12282. //zzz should break this proc up.
  12283. //zzz data length not accurate if not a multiple of 4.
  12284. //zzz should implement all the synch stuff.
  12285. //
  12286. //   Important:  We don't service additional packets while the channel handler runs.
  12287. //zzz
  12288. //zzz this code is obsolete and needs to be updated before it will work
  12289. //zzz
  12290.  
  12291. static void    LynxFWIMProcessIsochronousBlockPacket(
  12292.     LynxFWIMDataPtr                pLynxFWIMData,
  12293.     LynxPCLPtr                    pPCL,
  12294.     Ptr                            packetBuffer,
  12295.     UInt32                        packetSize)
  12296. {
  12297. /*zzz*/
  12298. #if 0
  12299. /*zzz*/
  12300.     FWIMAllocateIsochPortParamsPtr
  12301.                                 pFWIMAllocateIsochPortParams;
  12302.     LynxIsochPortDataPtr        pLynxIsochPortData;
  12303.     DCLCommandPtr                pDCLCommand;
  12304.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  12305.     UInt32                        channelNum,
  12306.                                 commandChannelNum;
  12307.     UInt32                        dataLength;
  12308.     Boolean                        disablePort = false;
  12309.  
  12310. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessIsochronousBlockPacket");
  12311.  
  12312.     // Get the pending FWIM command if there is one.
  12313.     pFWIMAllocateIsochPortParams = (FWIMAllocateIsochPortParamsPtr)
  12314.         &(pLynxFWIMData->fwimAllocateIsochPortParams);
  12315.  
  12316.     // We must have an active isochronous command and a matching channel number.
  12317.     //zzz how do we tell it's active.
  12318.     if (pFWIMAllocateIsochPortParams->fwimCommandParams.fwimCommandID !=
  12319.         kInvalidFWIMCommandID)
  12320.     {
  12321.         // Get isoch port data.
  12322.         pLynxIsochPortData = (LynxIsochPortDataPtr)
  12323.             pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
  12324.  
  12325.         // Get pending command type and channel number for this packet.
  12326.         commandChannelNum = pFWIMAllocateIsochPortParams->channelNum;
  12327.         channelNum = (pPacket[0] & kFWIsochChanNum) >> kFWIsochChanNumPhase;
  12328.  
  12329.         if (channelNum == commandChannelNum)
  12330.         {
  12331.             // Get the DCL command.
  12332.             pDCLCommand = pLynxFWIMData->pCurrentDCLCommand;
  12333.  
  12334.             // Compute data length for this buffer.
  12335.             dataLength = (((UInt32 *) pPacket)[0] & kFWIsochDataLength) >>
  12336.                          kFWIsochDataLengthPhase;
  12337.             if (dataLength & 0x03)
  12338.                 dataLength = (dataLength & 0xFFFFFFFC) + 4;        // round up to quadwords
  12339.  
  12340.             // Fill the isoch buffers.
  12341.             if (pDCLCommand != nil)
  12342.             {
  12343.                 LynxFWIMRunDCLProgram
  12344.                     (pLynxIsochPortData, (Ptr) pPacket, dataLength, &pDCLCommand);
  12345.                 pLynxFWIMData->pCurrentDCLCommand = pDCLCommand;
  12346.             }
  12347.  
  12348.             // If we've run out of buffers, disable port.
  12349.             if (pDCLCommand == nil)
  12350.                 disablePort = true;
  12351.         }
  12352.     }
  12353.  
  12354.     // Disable the port if we need to.
  12355.     if (disablePort)
  12356.     {
  12357.     
  12358. // NYI - If we reprogram the DMA comparators, we won't get any more Isoch.
  12359. // Maybe that would be a good idea.
  12360.  
  12361.     }
  12362.  
  12363. /*zzz*/
  12364. #endif
  12365. /*zzz*/
  12366.  
  12367.     // Add PCL back to active list.
  12368.     LynxFWIMAddAsyncRxPCL (pPCL);
  12369. }
  12370.  
  12371.  
  12372. ////////////////////////////////////////////////////////////////////////////////
  12373. //
  12374. // LynxFWIMProcessLockResponsePacket
  12375. //
  12376. //   This proc processes a lock response packet.
  12377. //zzz Verify destinationID, and sourceID.
  12378. //zzz Must check extended tCode.
  12379. //
  12380. // (IRM sends these)
  12381.  
  12382. static void    LynxFWIMProcessLockResponsePacket(
  12383.     LynxFWIMDataPtr                pLynxFWIMData,
  12384.     LynxPCLPtr                    pPCL,
  12385.     Ptr                            packetBuffer,
  12386.     UInt32                        packetSize)
  12387. {
  12388.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  12389.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  12390.     UInt32                        commandType;
  12391.     UInt32                        tLabel;
  12392.     UInt32                        rCode;
  12393.     UInt32                        dataLength;
  12394.     AbsoluteTime                timeRemaining;
  12395.     OSStatus                    status = noErr,
  12396.                                 responseStatus = noErr;
  12397.  
  12398. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessLockResponsePacket");
  12399.  
  12400.     dataLength = (pPacket[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase;
  12401.     if (dataLength & 0x03)
  12402.         dataLength = (dataLength & 0xFFFFFFFC) + 4;
  12403.  
  12404.     // Get the pending FWIM command if there is one.
  12405.     pFWIMAsynchCommandParams =
  12406.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  12407.  
  12408.     // We must have a pending lock command and a matching transaction label.
  12409.     if (pFWIMAsynchCommandParams != nil)
  12410.     {
  12411.         // Get pending command type, transaction label, and response code for this packet.
  12412.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  12413.         tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
  12414.         rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
  12415.  
  12416.         if ((commandType == kFWIMLock) &&
  12417.             (tLabel == pLynxFWIMData->transactionLabel) &&
  12418.             (pLynxFWIMData->tCode == kFWTCodeLock))
  12419.         {
  12420.             // Try to cancel timeout timer.
  12421.             status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
  12422.                                   &timeRemaining);
  12423.  
  12424.             // Complete command if we didn't time out.
  12425.             if (status == noErr)
  12426.             {
  12427.                 // Fill in command buffer.
  12428.                 if (rCode == kFWResponseComplete)
  12429.                 {
  12430.                     if (dataLength > pFWIMAsynchCommandParams->length)
  12431.                         dataLength = pFWIMAsynchCommandParams->length;
  12432.                     BlockCopy (&(pPacket[4]),
  12433.                                pFWIMAsynchCommandParams->buffer,
  12434.                                dataLength);
  12435.                 }
  12436.                 else
  12437.                 {
  12438.                     responseStatus = accessErr;//zzz not always the best
  12439.                 }
  12440.     
  12441.                 // Finish up command.
  12442.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  12443.                 FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, responseStatus);
  12444.             }
  12445.         }
  12446.     }
  12447.  
  12448.     // Add PCL back to active list.
  12449.     LynxFWIMAddAsyncRxPCL (pPCL);
  12450. }
  12451.  
  12452.  
  12453. ////////////////////////////////////////////////////////////////////////////////
  12454. //
  12455. // LynxFWIMSetupFIFOs
  12456. //
  12457. //   This proc sets up the FIFO sizes and thresholds.
  12458. //zzz this does have safety problems if there's stuff in the FIFOs.
  12459. //
  12460.  
  12461. static void    LynxFWIMSetupFIFOs(
  12462.     LynxFWIMDataPtr                pLynxFWIMData)
  12463. {
  12464.     LynxRegistersPtr            pLynxRegs;
  12465.  
  12466.     // Get base address for Lynx registers.
  12467.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  12468.     
  12469.     // pause the asynch receiver by disabling comparator, JKL *** should make sure GRF has drained?
  12470.     LynxFWIMDisableComparators(pLynxFWIMData);
  12471.         
  12472.     // Set up FIFOs depending on isochronous transmit mode.
  12473.     if (pLynxFWIMData->isochTransmitMode)
  12474.     {
  12475.         // Flush the FIFOs.
  12476.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12477.                 (UInt32 *) &pLynxRegs->fifoControlEnableAndTest,
  12478.                 (UInt32 ) EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH) ) )
  12479.             return;
  12480.         
  12481.         // Raise threshold so stuff won't accidentally go out.
  12482.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12483.                 (UInt32 *) &pLynxRegs->fifoTransmitThreshold,
  12484.                 (UInt32 ) EndianSwapImm32Bit (0x0000FFFF) ))
  12485.             return;
  12486.         
  12487.         // Set the FIFO sizes.
  12488.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12489.                 (UInt32 *) &pLynxRegs->fifoSize,
  12490.                 (UInt32 ) EndianSwapImm32Bit ( 
  12491.                                 (kIsochTransmitModeITFSize << kLynxITF_FIFOSZPhase) |
  12492.                                 (kIsochTransmitModeATFSize << kLynxATF_FIFOSZPhase) |
  12493.                                 (kIsochTransmitModeGRFSize << kLynxGRF_FIFOSZPhase) ) ))
  12494.             return;
  12495.  
  12496.         // Set the FIFO thresholds.
  12497.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12498.                 (UInt32 *) &pLynxRegs->fifoTransmitThreshold,
  12499.                 (UInt32 ) EndianSwapImm32Bit ( 
  12500.                                 (kIsochTransmitModeITFThreshold << kLynxITF_TRSHLDPhase) |
  12501.                                 (kIsochTransmitModeATFThreshold << kLynxATF_TRSHLDPhase) ) ))
  12502.             return;
  12503.  
  12504.         // Flush the FIFOs just to be sure.
  12505.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12506.                 (UInt32 *) &pLynxRegs->fifoControlEnableAndTest,
  12507.                 (UInt32 ) EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH) ))
  12508.             return;
  12509.     }
  12510.     else
  12511.     {
  12512.         // Flush the FIFOs.
  12513.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12514.                 (UInt32 *) &pLynxRegs->fifoControlEnableAndTest,
  12515.                 (UInt32 ) EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH) ))
  12516.             return;
  12517.  
  12518.         // Raise threshold so stuff won't accidentally go out.
  12519.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12520.                 (UInt32 *) &pLynxRegs->fifoTransmitThreshold,
  12521.                 (UInt32 ) EndianSwapImm32Bit (0x0000FFFF) ))
  12522.             return;
  12523.         
  12524.         // Set the FIFO sizes.
  12525.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12526.                 (UInt32 *) &pLynxRegs->fifoSize,
  12527.                 (UInt32 ) EndianSwapImm32Bit ( 
  12528.                                 (kDefaultITFSize << kLynxITF_FIFOSZPhase) |
  12529.                                 (kDefaultATFSize << kLynxATF_FIFOSZPhase) |
  12530.                                 (kDefaultGRFSize << kLynxGRF_FIFOSZPhase) ) ))
  12531.             return;
  12532.  
  12533.         // Set the FIFO thresholds.
  12534.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12535.                 (UInt32 *) &pLynxRegs->fifoTransmitThreshold,
  12536.                 (UInt32 ) EndianSwapImm32Bit ( 
  12537.                                 (kDefaultITFThreshold << kLynxITF_TRSHLDPhase) |
  12538.                                 (kDefaultATFThreshold << kLynxATF_TRSHLDPhase) ) ))
  12539.             return;
  12540.  
  12541.         // Flush the FIFOs just to be sure.
  12542.         if( LynxFWIMSafeRegisterWrite( pLynxFWIMData,
  12543.                 (UInt32 *) &pLynxRegs->fifoControlEnableAndTest,
  12544.                 (UInt32 ) EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH) ))
  12545.             return;
  12546.     }
  12547.     
  12548.     // turn asynch comparator back on
  12549.     LynxFWIMEnableComparators(pLynxFWIMData);
  12550.         
  12551. }
  12552.  
  12553.  
  12554. ////////////////////////////////////////////////////////////////////////////////
  12555. //
  12556. // LynxFWIMWaitForPHYPower
  12557. //
  12558. //   Called when we detect that the PHY is not powered. Shuts down the FWIM and
  12559. //   sets up a 5 second timer to wait for the PHY to start working again.
  12560. //
  12561. //   Shutting down a FWIM involves the following:
  12562. //
  12563. //        1) All outstanding async IOs returned with an error
  12564. //        2) All Interrupts Disabled.
  12565. //        3) All timers canceled.
  12566. //        4) FWIM configured to return errors from all subsequent requests.
  12567. //
  12568. void LynxFWIMWaitForPHYPower( 
  12569.     LynxFWIMDataPtr                pLynxFWIMData,
  12570.     Boolean                        sleepRequest )
  12571. {
  12572.     OSStatus                    status = noErr;
  12573.     AbsoluteTime                timeoutAbsolute;
  12574.     AbsoluteTime                timeRemaining;
  12575.     LynxRegistersPtr            pLynxRegs;
  12576.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  12577.     
  12578.     if( sleepRequest ) {
  12579.         // Try to cancel wakeup timer. Do this before checking for
  12580.         // already being hosed since we don't want the timer to go
  12581.         // off if we are Quiesced
  12582.         CancelTimer (pLynxFWIMData->phyPowerTimerID, &timeRemaining);
  12583.     }
  12584.         
  12585.     // Remember everything is broken
  12586.     if( !CompareAndSwap(0,1,(unsigned long *) &pLynxFWIMData->phyNotPowered) )
  12587.         return;    // Already knew about this problem, nothing to do.
  12588.         
  12589.     if( !sleepRequest ) {
  12590.         // Try to cancel wakeup timer. Do this after checking for
  12591.         // already being hosed since we do want the timer to go
  12592.         // off if we are in fact PHYless.
  12593.         CancelTimer (pLynxFWIMData->phyPowerTimerID, &timeRemaining);
  12594.     }
  12595.                           
  12596.     // Get the pending FWIM command if there is one.
  12597.     pFWIMAsynchCommandParams =
  12598.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  12599.  
  12600.     // Try to cancel timeout timer for current command.
  12601.     status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID, &timeRemaining);
  12602.  
  12603.     // Complete command if we didn't already time out.
  12604.     if (status == noErr)
  12605.     {
  12606.         // Finish up command.
  12607.         
  12608.         if( pLynxFWIMData->pPendingFWIMCommand ) {
  12609.             pLynxFWIMData->pPendingFWIMCommand = nil;
  12610.             FWIMCommandIsComplete (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID, accessErr);    // !!! what is the proper error here?!?
  12611.         }
  12612.     }
  12613.     
  12614.     // Prevent interrupts from happening so we don't get stuck in some unservicable interrupt loop.
  12615.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  12616.     pLynxRegs->pciInterruptEnable = 0;
  12617.     
  12618.     // If we are here as a result of an FSL sleep request then don't set the wakeup timer
  12619.     // and don't pretend we saw a reset.
  12620.     
  12621.     if( !sleepRequest ) {
  12622.         
  12623.         // If we have been initialized tell FSL about the reset. If we haven't finished initializing then
  12624.         // don't tell FSL about a reset before it is prepared to handle it.
  12625.         if( pLynxFWIMData->numPHYPorts ) {
  12626.             // Tell FSL a reset happened. This isn't strictly true but we need to tell the FSL something drastic has
  12627.             // happened on the bus.
  12628.             status = FWProcessBusReset (pLynxFWIMData->fwimID);
  12629.         }
  12630.     
  12631.         // set timer to wake up 5 seconds later and try to wake up the PHY
  12632.         timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (5 * durationSecond));
  12633.         status = SetInterruptTimer
  12634.                     (&timeoutAbsolute,
  12635.                      LynxFWIMAttemptPHYWakeup,
  12636.                      pLynxFWIMData,
  12637.                      &(pLynxFWIMData->phyPowerTimerID));
  12638.     }
  12639.  
  12640. }
  12641.  
  12642. ////////////////////////////////////////////////////////////////////////////////
  12643. //
  12644. // LynxFWIMWakeupReset
  12645. //
  12646. // Resets the bus after a delay.
  12647. //
  12648. static OSStatus    LynxFWIMWakeupReset(
  12649.     void                        *p1,
  12650.     void                        *p2)
  12651.  
  12652. {
  12653.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  12654.     UInt32                        phyReg;
  12655.  
  12656.     phyReg = LynxFWIMReadPhyRegister (pLynxFWIMData, kLynxPhyIBRAddress);
  12657.     phyReg |= kLynxPhyIBR;
  12658.     LynxFWIMWritePhyRegister (pLynxFWIMData, kLynxPhyIBRAddress, phyReg);
  12659.     
  12660.     return( noErr );
  12661.     
  12662. }
  12663.  
  12664.  
  12665. ////////////////////////////////////////////////////////////////////////////////
  12666. //
  12667. // LynxFWIMAttemptPHYWakeup
  12668. //
  12669. // Tries to wake up the PHY after we detected a no-power situation.
  12670. //
  12671. static OSStatus    LynxFWIMAttemptPHYWakeup(
  12672.     void                        *p1,
  12673.     void                        *p2)
  12674. {
  12675.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  12676.     AbsoluteTime                timeoutAbsolute;
  12677.     OSStatus                    status = noErr;
  12678.  
  12679.     // Assume for now everything is OK again
  12680.     pLynxFWIMData->phyNotPowered = 0;
  12681.     
  12682.     // If this fails, we'll schedule this task again automatically.
  12683.     LynxFWIMFullReset();
  12684.     
  12685.     // Make sure the bus gets reset since LynxFWIMFullReset only does it when we
  12686.     // execute it the first time. Theoretically we just got a reset but we might
  12687.     // not have seen it if the PHY was unpowered (and we had ints disabled etc.)
  12688.     // To avoid a reset storm we wait a second before issuing the reset
  12689.     
  12690.     // set timer to reset 1 second later
  12691.     timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationSecond));
  12692.     status = SetInterruptTimer
  12693.                 (&timeoutAbsolute,
  12694.                  LynxFWIMWakeupReset,
  12695.                  pLynxFWIMData,
  12696.                  &(pLynxFWIMData->phyPowerTimerID));
  12697.  
  12698.     return( noErr );
  12699.  
  12700. }
  12701.  
  12702. static void LynxFWIMFireBugMsg (
  12703.     LynxFWIMDataPtr                pLynxFWIMData,
  12704.     char                         *msg)
  12705. {
  12706.     UInt32                        sourceID;
  12707.  
  12708.     if( LynxFWIMSafeRegisterRead( pLynxFWIMData,
  12709.             (UInt32 *) &pLynxFWIMData->pLynxRegisters->busNumberNodeNumber,
  12710.             (UInt32 *) &sourceID ) )
  12711.         return;
  12712.         
  12713.     sourceID = EndianSwap32Bit( sourceID );
  12714.     
  12715.     LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_XMT, kFWSpeed100MBit, 4,
  12716.                       0x42420010, sourceID, 0x0, (strlen (msg) + 1) << 16,
  12717.                       strlen (msg) + 1, (UInt32 *) msg);
  12718. }
  12719.  
  12720. void LynxFWIMDisableVMUserCode( 
  12721.     LynxFWIMDataPtr                pLynxFWIMData )
  12722. {
  12723.  
  12724.     FWIMDisableVMUserCode();                    // Ordering is important here. We don't want to mark ourselves
  12725.     IncrementAtomic(&pLynxFWIMData->fwimBusy);    // busy while page faults can happen.
  12726.  
  12727.  
  12728. }
  12729.  
  12730.  
  12731. void LynxFWIMEnableVMUserCode(
  12732.     LynxFWIMDataPtr                pLynxFWIMData)
  12733.  
  12734. {
  12735.  
  12736.     DecrementAtomic(&pLynxFWIMData->fwimBusy);    // Ordering is important here. We don't want to allow page faults
  12737.     FWIMEnableVMUserCode();                        // while we are marked busy.
  12738.  
  12739. }
  12740.  
  12741.  
  12742. /////////////////////////
  12743. //  End of LynxFWIM.c  //
  12744. /////////////////////////